cjolley
cjolley

Reputation: 451

Linking error with template classes

I have a class that needs to call an external function in a variety of different contexts. I want to keep things flexible, so I'm using an interface (inspired by the 3rd edition of Numerical Recipes) that should work with functors, function pointers, etc. A simplified example looks like:

class MyClass {
  public:
    template <class T>
    MyClass(T &f_) { f = f_; }
  private:
    int (*f)(int);
};

int myFn(int i) {
  return i % 100;
}

int main() {
  MyClass test(myFn);
  return 0;
}

So far so good; g++ compiles this without any complaints. In my real application, there's a lot more code so I've got things split up among multiple files. For example,

test2.h:

#ifndef __test2__
#define __test2__

class MyClass {
  public:
    template <class T>
    MyClass(T &f_);    
 private:
    int (*f)(int);
};

#endif

test2.cpp:

#include "test2.h"

template <class T>
MyClass::MyClass(T &f_) {
  f = f_;
}

main.cpp:

#include "test2.h"

int myFn(int i) {
  return i % 100;
}

int main() {
  MyClass test(myFn);
  return 0;
}

When I try to compile this using g++ test2.cpp main.cpp, I get the following linking error:

/tmp/ccX02soo.o: In function 'main':
main.cpp:(.text+0x43): undefined reference to `MyClass::MyClass<int ()(int)>(int (&)(int))'
collect2: ld returned 1 exit status

It appears that g++ isn't aware of the fact that I'm also trying to compile test2.cpp. Any ideas about what might be going on here?

Thanks,

--craig

Upvotes: 0

Views: 210

Answers (1)

Luchian Grigore
Luchian Grigore

Reputation: 258618

Template classes must have their implementation visible to all translation units that use them, unless they are fully specialized.

That means you have to move the implementation in the header:

//test2.h
#ifndef __test2__
#define __test2__

class MyClass {
  public:
    template <class T>
    MyClass(T &f_);    
 private:
    int (*f)(int);
};

template <class T>
MyClass::MyClass(T &f_) {
  f = f_;
}

#endif

Upvotes: 1

Related Questions