views:

1508

answers:

8

Hi,

I just created this new class :

//------------------------------------------------------------------------------
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H
//------------------------------------------------------------------------------
#include <vector>
#include <GL/GLFW.h>
//------------------------------------------------------------------------------
template<class T>
class MultithreadedVector {

    public:

        MultithreadedVector();

        void push_back(T data);

        void erase(typename std::vector<T>::iterator it);

        std::vector<T> get_container();
    private:

        std::vector<T> container_;
        GLFWmutex th_mutex_;


};
//------------------------------------------------------------------------------
#endif // MULTITHREADEDVECTOR_H_INCLUDED
//------------------------------------------------------------------------------

The definition of the class :

//------------------------------------------------------------------------------
#include "MultithreadedVector.h"
//------------------------------------------------------------------------------
using namespace std;
//------------------------------------------------------------------------------
template<class T>
MultithreadedVector<T>::MultithreadedVector() {

    th_mutex_ = glfwCreateMutex();
}

template<class T>
void MultithreadedVector<T>::push_back(T data) {

    glfwLockMutex(th_mutex_);
    container_.push_back(data);
    glfwUnlockMutex(th_mutex_);

}

template<class T>
void MultithreadedVector<T>::erase(typename vector<T>::iterator it) {

    glfwLockMutex(th_mutex_);
    container_.erase(it);
    glfwUnlockMutex(th_mutex_);
}

template<class T>
vector<T> MultithreadedVector<T>::get_container() {


    return container_;

}

Now the problem is that when i try to use it in my code as a static member of another class :

// VehicleManager.h
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

#include "MultithreadedVector.h"
#include "Vehicle.h"
class Foo {

   public:
     // stuffs
   private:
     static MultithreadedVector<Vehicle> vehicles_; 
     ...
}

#endif

Then inside : VehicleManager.cpp

#include "VehicleManager.h"

MultithreadedVector<Vehicle> VehicleManager::vehicles_;

void VehicleManager::Method() {

  Vehicle vehicle;
  VehicleManager::vehicles_.push_back(vehicle);

}

But it doesn't compile :(, i get this error msg everytime :

C:\***\VehicleManager.cpp|188|undefined reference to `MultithreadedVector<Vehicle>::push_back(Vehicle)'|

I really don't understand why, especially that i have defined the static class member at the global scope of VehicleManager.cpp.

PS: I'm using Code::Blocks.

Thanks !

+2  A: 

The complete code of template implementation must be visible to the compiler at the point it sees the use of template so it can instantiate the template and compile it into object code that can be later linked.

Define the template code in the same header file as the template is declared.

sharptooth
+3  A: 

Most C++ compilers to not allow you to separate template declarations and template definitiions. You need to put the complete definition of your template classes in a single .h file, not split them into .h and .cpp files.

anon
fastest typist wins again. I'll delete my duplicate answer
Glen
Oh yes that's right, completey forgot that! thanks !
Amokrane
A couple of years ago, I would agree with you. However, at this point the most commonly used C++ compilers (Borland, MSVC, IBM, gcc) all support separating template declarations and template definitions via the `extern template` syntax and explicit instantiation.That said, this won't be standard until C++0x happens.
Jeff Leonard
+1  A: 

You seem to have a copy&paste error in VehicleManager.h:

#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

This prohibits the inclusion of the header file, where class Foo is defined.

jhwist
+1  A: 

You cannot write the template implementation in the cpp file in most of the cases. Move the template implementation to the header file so that compiler can instantiate it properly.

Naveen
+4  A: 

That's what will happen when blindly moving a class template implementation to a cpp file.

To make that work, you must know exactly for what types of T you will instantiate the class template and specify them in the cpp file.

In this case, put this in the cpp file:

template class MultithreadedVector<Vehicle>;

Note that the cpp file must know about Vehicle then.

Johann Gerell
Thanks, so separating the template declaration and definition is possible! But, obviously this isn't a good practice for programming templates. So i'll put the declaration inside the .h file anyway!
Amokrane
+1 I like it - but are you sure it will work without C++0x's extern template class MultithreadedVector<Vehicle> in the client code that uses the .h file?
Faisal Vali
It _can_ be good practice in the special case when you know _exactly_ all the possible types you will use to instantiate the class template. In the general case though, you need to keep it in h files, for example if you're providing an SDK and cannot completely anticipate all use cases.
Johann Gerell
Ok thank you for the explanation!
Amokrane
Actually Amokrane, what you want *can* be done. See my answer below.
T.E.D.
@Faisal Vali, extern doesn't have to do with this. extern is used as a mechanism to tell the compiler "In this TU, please don't instantiate that template - i will provide an instantiation in another TU", and is kind of the opposite of explicit instantiation. It can dramatically reduce compile time since no more useless multiple instantiations are generated.
Johannes Schaub - litb
+1  A: 

Apart from the other answers:

You have to guard get_container() as well. This method basically copies the container_ elements and hence must be guarded.

template<class T>
vector<T> MultithreadedVector<T>::get_container() 
{
    return container_;
}
aJ
What do you mean ? I actually, did this!
Amokrane
You need to use Mutex to guard this method as well.
aJ
Ah ok thanks :) will do it!
Amokrane
+1  A: 

A template in a way is kind of an advanced, specialized kind of macro. You cannot actually compile a template defintion separately like it looks like you are trying to do.

For most people, this means they don't even bother to separate teplate definitions from their declarations. I have one co-worker who takes this a step further, and refuses to separate non-template definitions and declarations too.

If you want to put the definition of a template from the declaration, you do have a couple of options though.

The first option is to use the C++ "export" keyword. The problem with this seemingly simple solution is that nobody supports it. It is too tough for compiler writers to implement.

The second option is to use a third type of file, often tagged ".ipp", for the declarations. The trick here is that it is still a file that must be "#included", but being a separate file, you only have to include it in ".cpp" files. I've found my linker doesn't like it if I #include a ".ipp" in more than one ".cpp" file in a single program, so you do have to pick one be the includer.

T.E.D.
Interesting, thanks for the information !Didn't know about the ipp files :
Amokrane
+1  A: 

I think there are two cases how one can use templates

  1. Providing generic code for an arbitrary set of conforming types
  2. Providing generic code for a fixed set of types

For the second one, you don't need to put templates into the header: Since you know beforehand, precisely, with what types your template is used. You can very well define a class template's member function, or a function template in a separate translation unit, without linker errors. Some people keep teaching others that this is not possible, and confuse the matter by this.

But i think it depends on these two cases whether you want to separate declaration and definition into different translation units or not.

  • If you want to use case 1, you always want to have the definition in the header (whether included by special named files, like .ipp, .tcc or whatever). I only know of one C++ frontend that supports separating definition from declarations even in this case, which is the EDG (edison design group) frontend, used by the intel and comeau compilers, that implement export. That keyword is seen as a misfeature by some, and most compilers don't implement it.

  • And if you want to use case 2, it's no good to put the definitions into the header, because there would be no reason to do so: You will just explicitly instantiate the needed functions and classes for the fixed set of types. In this second scenario, you use the template to save yourself from the burden to maintain possibly redundant code, and have the option open to introduce special behavior for some types in some cases.

Your scenario is clearly a case 1 situation, and so you will have to put your definitions into the header.

Johannes Schaub - litb