Question

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 !

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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.

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.

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.

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

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top