1

See my demo code below:

b.hpp:

#ifndef B_HPP
#define B_HPP

namespace debug {
class test {
public:
  template <class T> void foo(T a); 
private:
  int a;
};
}
#endif

b.cpp:

#include <iostream>
#include "b.hpp"

namespace debug {

template <class T>
void test::foo(T a) {
  std::cout << "debug" << std::endl;
}

}

testb.cpp:

include "b.hpp"

int main(int agrc, char *argv[])
{
  debug::test a;
  int c = 5;
  a.foo(c);
  return 0;
}

I compile it with

g++ -std=c++11 testb.cpp b.cpp'

and get a error:

/tmp/ccnjR5S4.o: In function `main':
testb.cpp:(.text+0x1c): undefined reference to `void debug::test::foo<int>(int)'
collect2: error: ld returned 1 exit status

What's the problem?

If I put main function in b.cpp and compile b.cpp, it 's ok. Why?

Thanks!

xunzhang
  • 2,838
  • 6
  • 27
  • 44
  • Short answer, the compiler never instantiates `test::foo` and so the function doesn't exist anywhere when it comes time to link. Why can't it instantiate? Because the full definition isn't available. – greatwolf Nov 09 '13 at 07:49

1 Answers1

2

This is one of the cases where you need explicit instantiation, or to move code back into b.hpp. This arises because the implementation of debug::test::foo isn't visible when you compile testb.cpp, and the compiler has no way of knowing what might be needed when it compiles b.cpp.

To explicitly instantiate debug::test::foo<int>, add the following line to b.cpp:

#include <iostream>
#include "b.hpp"

namespace debug {

template <class T>
void test::foo(T a) {
  std::cout << "debug" << std::endl;
}

// Explicitly instantiate test::foo<int>
template void test::foo<int>(int);   // <-- add this line

}

Alternately, if you do not know all the ways this template might get instantiated, move its definition back into the class definition in the header. Ugly, but it'll work.

Some compilers do cross-compilation unit template instantiation, but as you've discovered, g++ isn't one of them. (At least, not as it's configured on my system.)

Edit: As @juanchopanza pointed out above, this thread gives a good explanation of what's going on: Why can templates only be implemented in the header file?

Community
  • 1
  • 1
Joe Z
  • 17,413
  • 3
  • 28
  • 39