开发者

G++ linker does not find template class constructor and member function if their definition is separated from their use [duplicate]

This question already has answers here: Closed 11 years ago.

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开发者_如何学JAVA 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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜