Template<typename T> compilation error

Hi everyone!

When compiling a program that uses the following class, I get a tons of strange compilation errors about a undefined reference to `ZN8DebugLog5loglnIPKcEEvT'.

DebugLog.h:

#ifndef DEBUGLOG_H
#define DEBUGLOG_H
#include "Arduino.h"

class DebugLog {
  private:
    bool sendToSerial;

  public:
    DebugLog(bool sendToSerial);
    void begin();

    template<typename T> void log(T value);
    template<typename T> void logln(T value);
};
#endif

DebugLog.cpp:

#include "DebugLog.h"

DebugLog::DebugLog(bool sendToSerial){
  this->sendToSerial = sendToSerial;
}

void DebugLog::begin() {
  if (sendToSerial) {
    Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
    delay(2000);
    while (!Serial)
      ;
  }
}

template<typename T> void DebugLog::log(T value) {
  if (sendToSerial){
    Serial.print(value);
  }
}

template<typename T> void DebugLog::logln(T value) {
  if (sendToSerial){
    Serial.println(value);
  }
}

Has anyone faced a similar issue?

I think that it will help if you posted the errors (using code tags) and tell us which board you are using.

For me, this is advanced C++ and can't help you with it.

I think I just found the solution.

By looking how EEPROM class is made, it also uses a generic undefined typename and by writing the function body in the header file it works!

It may not be the jedi way (as far as i know it is a bad practice write code inside the .h), but it gets the job done soo....

The new .h:

#ifndef DEBUGLOG_H
#define DEBUGLOG_H

#include "Arduino.h"

class DebugLog {
  private:
    bool sendToSerial;

  public:
    DebugLog(bool sendToSerial);
    void begin();

    template<typename T> void log(T value) {
      if (sendToSerial){
        Serial.print(value);
      }
    }

    template<typename T> void logln(T value) {
      if (sendToSerial){
        Serial.println(value);
      }
    }
};
#endif

Yup, just discovered.
Thx anyway!
Not sure but I think this behaviour can be "resolved" by changing the compiling stage in the IDE.
Maybe by how the preprocessor looks up all the usages and writes a foo for each of them.

Because the compiler must instantiate the templated function into a real function with the actual data type substituted for the "T". It needs to do that when it's compiling the file where the function is invoked (eg the .ino file), not when it's compiling the .cpp file that holds the non-templated part of the class definition.

The only information that the compiler has when compiling the .ino is what's #include(d). That's the class's .h file so that's where the templated function definition needs to go.

Yup.

Correct.

2 Likes

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