1

Possible Duplicate:
Why can templates only be implemented in the header file?

While developing a little parser with some type-awareness, I have come across the following puzzle. In short:

GNU g++ “forgets” a template member function definition unless it is defined in the same file where it is used.

Any ideas why?

The Files of the Case

To isolate the problem, I have stripped down the code to three files:

The header file Temple.hpp:

#ifndef _TEMPLE
#define _TEMPLE

template <class T> class Temple {
    private:
        T deity;
    public:
        Temple ( T value );
        T see ();
};

#endif

Then the corresponding C++ implementation file Temple.cpp:

#include "Temple.hpp"
template <class T> Temple<T>::Temple ( T value ) : deity( value ) {}
template <class T> T Temple<T>::see () { return deity; }

And finally a main application calling the stuff in a file templetest.cpp:

#include "Temple.hpp"
int main () {
    bool b(false);
    Temple<bool> t( b );
    t.see();
}

What should happen is that a local variable Temple<bool> t is constructed and then provides the (template-expanded) method bool see() as defined by the template.

Compilation as it fails ☹

However, when I try to compile the C++ sourcecode using

g++ *.cpp

(or naming the files explicitly, as well), I get a linker error on gcc version 4.2.1:

/tmp//ccWAFJDF.o(.text+0x24): In function `main':
: undefined reference to `Temple<bool>::Temple(bool)'
/tmp//ccWAFJDF.o(.text+0x2f): In function `main':
: undefined reference to `Temple<bool>::see()'
collect2: ld returned 1 exit status

and somewhat less verbose on gcc 4.0.1:

/usr/bin/ld: Undefined symbols:
Temple<bool>::see()
Temple<bool>::Temple(bool)
collect2: ld returned 1 exit status

Anyway, from this I conclude that templetest.cpp can access neither the constructor nor a member function of the concrete template class.

Compilation as it works ☻

So far so bad, but there is another way of compiling, namely putting all code into just one source file and then compiling. Surprisingly, this goes well. You can try the approach simply using stdin-streaming:

cat *.cpp | g++ -x c++ -

The same success is the result if the file Temple.cpp is manually merged into Temple.hpp to yield:

template <class T> class Temple {
    private:
        T deity;
    public:
        Temple ( T value );
        T see ();
};

template <class T> Temple<T>::Temple ( T value ) : deity( value ) {}
template <class T> T Temple<T>::see () { return deity; }

and this is subsequently compiled using

g++ templetest.cpp

It appears that GNU CC can only remember that the member function definitions in Temple.cpp belong to the template class if they are in the same file.

Community
  • 1
  • 1
  • You should prefix your template function declarations with `inline` if you are not defining them in the class. Otherwise you will get linker errors. – GWW Jul 14 '11 at 19:03
  • 1
    This is pretty standard: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12 – ldog Jul 14 '11 at 19:06
  • 1
    @GWW - one should only prefix the functions with `inline` if one wants the inline behavior. It is perfectly acceptable to have non-inline template functions in a CPP. Just use explicit instantiation. – Robᵩ Jul 14 '11 at 19:21
  • @Rob: Sorry, I didn't provide enough context. I am referring to defining them in the header file. – GWW Jul 14 '11 at 19:32
  • Well, then, that's excellent advice. – Robᵩ Jul 14 '11 at 19:36

1 Answers1

1

In main.c, at the moment you declare a variable of type Temple<bool>, you instantiate that type. In order to instantiate a templated type, you must have access to all of the implementation of that type.

You have two choices.

The first, and conventional, choice is to place the entire implementation in the header file, and delete the Temple.cpp file:

// UNTESTED
template <class T> class Temple {
  private:
    T deity;
  public:
    Temple ( T value ) : deity(value) {}
    T see () { return deity; }
};

This way, any user of your template can instantiate it with any type they choose.

The second, and less conventional, way is to explicitly instantiate Temple<bool> in the only location that has access to the entire implementation, namely temple.cpp:

// temple.cpp
...
// At the very end of the file:
template class Temple<bool>;

Be warned, however, that the users of the templated class Temple can only use instances that you have created. In this case, they may only ever use bool.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308