Sign in to follow this  

Templates - simple question

This topic is 4300 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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;
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 ).

Share this post


Link to post
Share on other sites
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. (...)"

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Quote:

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).


Yes, this is a good point that I missed entirely. Oops.

Share this post


Link to post
Share on other sites

This topic is 4300 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this