Templates - simple question

Started by
9 comments, last by jpetrie 18 years, 1 month ago
Hi, I was just trying to program a simple C++ template class example, since I've never used them before in my work. I'm basically re-implementing the vector class (using the vector class :)) I'm getting linker errors (Code::Blocks IDE w/included mingw compiler on Windows)... any ideas? Errors:

Linking console executable: Z:\code\c++\templates\templates.exe
.objs\main.o:main.cpp:(.text+0x170): undefined reference to `vect_general<int>::vect_general()'
.objs\main.o:main.cpp:(.text+0x182): undefined reference to `vect_general<float>::vect_general()'
.objs\main.o:main.cpp:(.text+0x19c): undefined reference to `vect_general<int>::push(int)'
.objs\main.o:main.cpp:(.text+0x1af): undefined reference to `vect_general<int>::push(int)'
.objs\main.o:main.cpp:(.text+0x1c2): undefined reference to `vect_general<int>::push(int)'
.objs\main.o:main.cpp:(.text+0x1d6): undefined reference to `vect_general<float>::push(float)'
.objs\main.o:main.cpp:(.text+0x1ea): undefined reference to `vect_general<float>::push(float)'
.objs\main.o:main.cpp:(.text+0x1fe): undefined reference to `vect_general<float>::push(float)'
.objs\main.o:main.cpp:(.text+0x210): undefined reference to `vect_general<float>::~vect_general()'
.objs\main.o:main.cpp:(.text+0x222): undefined reference to `vect_general<int>::~vect_general()'
.objs\main.o:main.cpp:(.text+0x25d): undefined reference to `vect_general<float>::~vect_general()'
.objs\main.o:main.cpp:(.text+0x287): undefined reference to `vect_general<int>::~vect_general()'
collect2: ld returned 1 exit status
Process terminated with status 1 (0 minutes, 12 seconds)

Thanks. main.cpp:

#include <iostream>
using namespace std;
#include "vect_general.h"

//typedef vect_general <int> vi;
//typedef vect_general <float> vf;

int main()
{
    int i;
    vect_general <int> vi1;
    vect_general <float> vf1;

    vi1.push(0);
    vi1.push(1);
    vi1.push(2);

    vf1.push(0.05f);
    vf1.push(0.15f);
    vf1.push(0.25f);



	return 0;
}

vect_general.h:

#ifndef VECT_GENERAL_H
#define VECT_GENERAL_H

#include <vector>
using namespace std;

template <class T>
class vect_general
{
public:
    vect_general();
    ~vect_general();
    void push(T elem);
    T pop();
//private:
    vector <T> v;
};

#endif

vect_general.cpp:

#include "vect_general.h"
#include <vector>
using namespace std;

template <class T>
vect_general<T>::vect_general()
{
}

template <class T>
vect_general<T>::~vect_general()
{
}

template <class T>
void vect_general<T>::push(T elem)
{
    v.push_back(elem);
}

template <class T>
T vect_general<T>::pop()
{
    T temp = v.back();
    v.pop_back();
    return temp;
}

--== discman1028 ==--
Advertisement
Template implementations must be included into the file that uses the vector, unless you happen to have a compiler that supports the "export" keyword( which, looking at your post closer, you don't ).

So, copy your .cpp file into your .h file ( minus the include ) and try again.
Quote:Original post by rip-off
Template implementations must be included into the file that uses the vector


You mean std::vector or my class? According to this, you can have them in a separate cpp....


discman1028
--== discman1028 ==--
Quote:Original post by discman1028
Quote:Original post by rip-off
Template implementations must be included into the file that uses the vector


You mean std::vector or my class?


Your class. If you look closely at the std::vector source, you'll find they do the same( via a #include ).
Quote:Original post by discman1028
Quote:Original post by rip-off
Template implementations must be included into the file that uses the vector

Else, according to this, you can have them in a separate cpp....


discman1028


Straight from your own source...
Quote:
"Implementing template member functions is somewhat different compared to the regular class member functions. The declarations and definitions of the class template member functions should all be in the same header file. The declarations and definitions need to be in the same header file. (...)"
Thanks... I misread.

--== discman1028 ==--
Quote:Original post by discman1028
According to this, you can have them in a separate cpp....


EDIT: rip-off already pointed this out
That document is from 1997... Also I haven't looked through it all, but try to read the section called "Implementing class template member functions" here they show you it doesn't work.

You can use the export keyword, in theory, but very few compilers supports it, the only compiler I know which supports it's Comeau's.

If you really want to seperate them you can do something like this:

vect_general.h (notice the include near the bottom):
#ifndef VECT_GENERAL_H#define VECT_GENERAL_H#include <vector>using namespace std;template <class T>class vect_general{public:    vect_general();    ~vect_general();    void push(T elem);    T pop();//private:    vector <T> v;};// CHANGED#include "vect_general.cpp"#endif


EDIT:
Also you need include guards in your .cpp file, like this:
#ifndef VECT_GENERAL_CPP#define VECT_GENERAL_CPP// .... stuff ....#endif
Very cool... thanks CTar.
--== discman1028 ==--
Alternatively, you can have the header file include an implementation file that does not end .cpp or .c (or any other extension that your IDE will automatically recognize as compilable source). Then you don't need to bother with the include guards in the .cpp file. Typically I use the .inl extension for this, so my template source files look like:

#ifndef HEADER_H_#define HEADER_H_// template class declaration#include "foo.inl" // <-- implements declarted class#endif


You no longer need the guards in the .cpp because the compiler will not attempt to compile the .inl file.
Quote:Original post by jpetrie
You no longer need the guards in the .cpp because the compiler will not attempt to compile the .inl file.


The guards won't help if the compiler is compiling the code in question (#defines from compiling one translation unit don't carry over to another). The need for guards in this case is orthogonal to the extension entirely. You don't really "need" the guards per se, since the implementation file (.inl, or I use .tpp) will be the only header including it, and it will do so from within it's own guards. That said, I put them in anyways out of habit.

Since there's no real reason to compile said implementation file, it should avoid being named .cpp. Reserve that extension for the implementations of non-templated functions related to the header in question, if you desire, as these don't need to be included in every translation unit that uses them. This would not be included by your header, only the .inl/.tpp containing the template (or inline) functions.

This topic is closed to new replies.

Advertisement