views:

49

answers:

5

Hi! This is wholy mysterious to me. I'm using g++ on ubuntu, and this is some of my code (with class names change, but nothing else because I'm still using stubs everywhere):

Bob.hpp

template <class A>
class Bob : public Jack<Chris, A>
{
    public: 

        Bob(int x1, int x2, float x3 = 1.0, float x4 = 2.0, float x5 = 3.0) throw(Exception);
        virtual ~Bob();
};

I implemented in another file like this:

Bob.cpp

template <class A>
Bob<A>::Bob(int x1, int x2, float x3, float x4, float x5) throw(Exception)
{

}

template <class A>
Bob<A>::~Bob()
{

}

and I used it like this:

main.cpp

int main()
{
    Bob<Alice> instance(1, 2);
}

Compiling with:

g++ -c Bob.cpp -o Bob.o
g++ -c main.cpp -o main.o
g++ -L"libs" -llib main.o Bob.o prog

gives me main.o: In function main': main.cpp:(.text+0x1fd): undefined reference toBob::Bob(int, int, float, float, float)' collect2: ld returned 1 exit status

I am completely stumped. Changing the order with the g++ linking stage makes no difference. Compiling the object files generates no problems. And Why an undefined reference when I implemented the constructor? If anyone could shed any light on this, it's be much appreciated.

+1  A: 

The declarations and definitions of the class template member functions should all be in the same header file.

When compiling Bob.cpp, the compiler has both the declarations and the definitions available. At this point the compiler does not need to generate any definitions for template classes, since there are no instantiations. When the compiler compiles main.cpp, there is an instantiation: template class Bob<Alice>. At this point the compiler has the declarations but no definitions!

Kirill V. Lyadvinsky
A: 

Perhaps you forgot to #include "Bob.hpp" in main.cpp?

As for templates, how they work and why the class functions need to be all be in one .h file

http://www.experts-exchange.com/Programming/Languages/CPP/A_1199-Seperating-C-template-declaration-and-implementation.html

David
They don't have to be in one .h file. They have to be present in *all implementation files*. The latter is usually achieved by #include-ing the definitions in all implementation files. But still it is not necessary to do it through one .h file.
AndreyT
That's about how it is usually done. All in one .h file that is included anywhere it is used (see std::string for example).
David
A: 

In addition to the issues raised by others, libraries must come last on the GCC command line. Instead of:

g++ -L"libs" -llib main.o Bob.o prog

you want:

g++ -L"libs"  main.o Bob.o prog -llib
anon
A valid comment, but not really an answer to the question. I did know this, the order ways a leftover from another fixing attempt where I changed include and linking order a lot.
TMP
+1  A: 

You need to move the code from Bob.cpp into Bob.hpp. When the compiler sees the definitions of Bob::Bob and Bob::~Bob in Bob.cpp, it does not know what types of Bob are actually going to be instantiated (i.e. Bob<int> vs Bob<SomeClass> and the code for them isn't generated. Alternatively, you can still place the code in the Bob.cpp file, but you need to declare which types of Bob are going to be instantiated, e.g.: Inside of Bob.cpp:

template
class Bob<Alice>;
acanaday
A: 

Where do you think the constructor of Bob<Alice> should be defined? It wasn't defined in Bob.cpp, because there was no mention of a Bob<Alice> in Bob.cpp. There was a template, which could have been used to define Bob<Alice> when Bob.cpp was compiled into Bob.o, but it wasn't.

Put the template definition in Bob.hpp, or Bob<Alice> in Bob.cpp.

Beta
Thank you for the answer! It's nice and concise so I would accept it, but others have a little more "meat" and deserve it a bit more.
TMP