tags:

views:

140

answers:

4

I'm trying to write a simple vector class with templates, but when I split it into a .h and a .cpp file, I get these errors:

undefined reference to vector<int>::vector()' undefined reference to vector::add(int)' undefined reference to vector<int>::add(int)' undefined reference to vector::remove(int)'

the code: http://pastie.org/623584

A: 

You can not split the declaration and implementation of the template class into .h & .cpp . It should be there in .h itself. When vector in main(), compiler tries to create an instance of class vector. For doing this it needs to know the complete implementation of the class, so you need to write the whole template class in .h itself.

Naveen
Not true, you just have to declare what types you want you template class to be defined for in your .C file.
Brian Gianforcaro
I know.. but I don't want to confuse a newbie to templates by doing it.
Naveen
+3  A: 

Either follow Naveen's advice and keep it in header or add

template class vector<int>;

To your .cc file. But you'd have to instantiate it for all possible template arguments then.

Michael Krelin - hacker
A: 

There are several ways to avoid such linking problems, it should be very interesting for you to read http://www.parashift.com/c%2B%2B-faq-lite/templates.html#faq-35.15

It explains you the different solutions. If you do not instantiate template, you have to put definitions and implementations in your .h, but if you do you have to add something like

template class vector<int>;

or(and)

template class vector<double>;

in your .cpp, according the templates you instantiate.

Nadir SOUALEM
A: 

The reason for your problem lies with file organisation in C++.

About headers and sources

Sources are files that are compiled into binary "object files", and then linked together to produce the final binary (either a library or an executable).

But for one source to use the code defined in another source, they must share the "declarations" of the code. Thus, the declaration must be put in shared files we will call header files.

Usually, the code in headers is not "true code", only declaration of the existence of this true code.

This is what you did with your custom vector: Put the declaration on the header, and the implementation on the source, and include the header in the main.

About inlining

Now, some "true code" can be put inside the headers, usually by prefixing it with the keyword "inline".

Again, this is not really true code: The compiler and the linker will figure what to do with it, but it can either:

  • Move the function code into an "object file" and have all the other "object files" link with it there
  • Inline the code where the inlined function is used
  • The two solution above at the same time

But the inlined function could well disappear from the binary if it is not used.

About templates

Templates are somewhat like declaration: They are not "true code", but "potential code". It's even more "potential" than inline code because the template code will need to be instanciated for the right template parameters.

Like for any other code, to use a template code, your source file must have access to the declaration. But in this case, the declaration of a template is both the "potential declaration" and the "potential implementation", which will be instanciated by the compiler for the right types you're using.

There are other ways to work with templates, but this is the way that will always work.

One last advice

When working with templates (or inlined code) it can be very very convenient to break down the header into multiple files (for example, when dealing with circulary dependancies of declaration).

Example:

file: MyObject.hpp

#include <MyObject_header.hpp>
#include <MyObject_source.hpp>

file: MyObject_header.hpp

class MyObject
{
   // Etc.
} ;

file: MyObject_source.hpp

#include <MyObject_header.hpp>

MyObject::MyObject()
{
   // etc.
}

// etc.
paercebal