Re: templates...C++ code in the .h file

It works and works well, but I've been told it's bad to have code in the .h file.

In general, it is. Sometimes, though, especially with templates, you just have to. Ignore people who are dogmatic about it being wrong.

Paul is right, no need for two files when one will do.

If you want to only allow certain variations (of the template parameters) you can separate the definition from the declaration in a cpp. This prevents a user from declaring any template that isn't instantiated in the cpp.

Hi,

Is it me not understanding something or the line "value = temp.type;" in the second function is wrong?

It should be "temp.type = value;" before the loop just like the first function, isn't it?

Delta_G:
I've been using this same file in projects left and right for a while now. It works and works well, but I've been told it's bad to have code in the .h file. For some reason though, I can't make it work out with a template function.

Is there a better way to do this instead of just putting the code in the .h file like I have?

EEPROM_Funcs.h

#ifndef EepromFuncs_h

#define EepromFuncs_h

#include <EEPROM.h>

template
void writeToEEPROM(int address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  }
  temp;

temp.type = value;
  for (int i = 0; i < sizeof(T); i++)
  {
    EEPROM.write(address + i, temp.b[i]);
  }
}

template
void readFromEEPROM(int address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  }
  temp;

for (int i = 0; i < sizeof(T); i++)
  {
    temp.b[i] = EEPROM.read(address + i);
  }
  value = temp.type;
}

#endif

Arduino IDE GUI has a obscure "pull-down" button in upper right corner of monitor screen, almost invisible.
You obviously know what its function is.

I have close to 100 of "new tabs" ( another Arduino coined term ) in my project.
IMHO after current "tab" gets over 1000 lines is is time for new one.
That is why "include" was invented, duh!

The BIG NO_NO is putting SYSTEM #include< include this file> ANYWHERE BUT the main x.ino file!

Because it just does not work !
Life is great, and will be better with Windows 10 and new Arduino IDE 10

I don't think it is particularly bad for template functions. In fact you have to. Otherwise the compiler won't know what code to generate if the implementation was in a different file than the include file.

Imagine, for example, you used writeToEEPROM multiple time, once for a float, once for a long, once for an int. If you had the code in a separate file, how would the compiler know what sort of template function to generate? It wouldn't.

You can make the whole thing one .ino file like this:

#include <EEPROM.h>

template<class T> void writeToEEPROM(int address, T& value);  // prototype
template<class T> void writeToEEPROM(int address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  }
  temp;

  temp.type = value;
  for (int i = 0; i < sizeof(T); i++)
  {
    EEPROM.write(address + i, temp.b[i]);
  }
}

template<class T> void readFromEEPROM(int address, T& value);  // prototype
template<class T> void readFromEEPROM(int address, T& value)
{
  union {
    T type;
    byte b[sizeof(T)];
  }
  temp;

  for (int i = 0; i < sizeof(T); i++)
  {
    temp.b[i] = EEPROM.read(address + i);
  }
  value = temp.type;
}

void setup ()
  {
  float foo = 42;
  writeToEEPROM (0, foo);
  float bar;
  readFromEEPROM (0, bar);
  }  // end of setup

void loop ()
  {
    
  }  // end of loop

To make it compile you have to add in the function prototype lines.

AbleA:
Hi,

Is it me not understanding something or the line "value = temp.type;" in the second function is wrong?

It should be "temp.type = value;" before the loop just like the first function, isn't it?

No, the code is OK. The data has been read into the union, in array "b". Then as the last thing in the function the variable "type" (not a name I particularly like) is returned to the caller, which passed "value" by reference.

Can you please clarify?

Value is a pointer, isn't it? and the union temp declared in function scope?

Though temp hold the correct data it seems to me that "value = temp.type;" makes it point to an out of scope variable once the function returns.

What am I missing?

Thanks

Thanks you for the detail explanation.

I used to think and count on (in other languages) that var by ref is actually done by passing a pointer hence my confusion.

If I get it right the compiler is actually passing a pointer but treats the assignment to "value" as assignment of variable content and not its address?

If I get it right the compiler is actually passing a pointer but treats the assignment to "value" as assignment of variable content and not its address?

Effectively, yes. Passing by reference saves a lot of putting "*" in front of variables. It also saves you from accidentally changing the pointer.

Thanks again. I got that part now :slight_smile:
But do excuse my curiosity...

In that case ins't that code somewhat inefficient?

Wouldn't it be more efficient to read the EEPROM directly into the pointed var?
Especially when considering that the function will usually deal with large variables?

Wouldn't it be more efficient to read the EEPROM directly into the pointed var?

For one variable, yes. For a collection of variables, as in a struct, no.

That code Delta_G posted uses a temporary variable, so it would be mildly inefficient, because you are copying into the variable and then assigning it (a second copy).

However the code on Arduino Playground - HomePage does it a bit differently:

#include <EEPROM.h>
template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          EEPROM.write(ee++, *p++);
    return i;
}

template <class T> int EEPROM_readAnything(int ee, T& value)
{
    byte* p = (byte*)(void*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
          *p++ = EEPROM.read(ee++);
    return i;
}

That uses a pointer to the actual variable (supplied by reference) and there is therefore no temporary variable, and no second copy. So that would be more efficient (and use less temporary memory).

Found that code and then this thread, liked the union idea but then...

Anyway I understand more now.

My thanks to all responders

The union can be handy if you want to return the value (as opposed to passing it by reference) because then you need a temporary copy to build up, before returning it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.