0

我刚刚创建了这个新类:

//------------------------------------------------------------------------------
#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
//------------------------------------------------------------------------------

类的定义:

//------------------------------------------------------------------------------
#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_;

}

现在的问题是,当我尝试在我的代码中将它用作另一个类的静态成员时:

// VehicleManager.h
#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

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

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

#endif

然后在里面:VehicleManager.cpp

#include "VehicleManager.h"

MultithreadedVector<Vehicle> VehicleManager::vehicles_;

void VehicleManager::Method() {

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

}

但它没有编译:(,我每次都会收到这个错误消息:

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

我真的不明白为什么,尤其是我在 VehicleManager.cpp 的全局范围内定义了静态类成员。

PS:我正在使用 Code::Blocks。

谢谢 !

4

8 回答 8

5

这就是盲目地将类模板实现移动到 cpp 文件时会发生的情况。

为了使这个工作,您必须确切地知道您将实例化类模板并在 cpp 文件中指定它们的 T 类型。

在这种情况下,将其放入 cpp 文件中:

template class MultithreadedVector<Vehicle>;

请注意,cpp 文件必须知道Vehicle那时。

于 2009-06-16T13:14:38.713 回答
4

大多数 C++ 编译器不允许您分离模板声明和模板定义。您需要将模板类的完整定义放在单个 .h 文件中,而不是将它们拆分为 .h 和 .cpp 文件。

于 2009-06-16T13:12:27.050 回答
2

模板实现的完整代码必须在编译器看到模板的使用时对它是可见的,以便它可以实例化模板并将其编译成可以稍后链接的目标代码。

在声明模板的同一头文件中定义模板代码。

于 2009-06-16T13:11:23.120 回答
2

我认为有两种情况可以使用模板

  1. 为任意一组符合的类型提供通用代码
  2. 为一组固定类型提供通用代码

对于第二个,您不需要将模板放入标题中:因为您事先知道您的模板使用什么类型。您可以很好地定义类模板的成员函数,或在单独的翻译单元中定义函数模板,而不会出现链接器错误。有些人一直在教导别人这是不可能的,并以此混淆了这件事。

但我认为这取决于这两种情况是否要将声明和定义分成不同的翻译单元。

  • 如果您想使用案例 1,您总是希望在标题中包含定义(无论是否包含在特殊命名文件中,例如.ipp.tcc或其他)。我只知道一个 C++ 前端即使在这种情况下也支持将定义与声明分离,它是英特尔和 Comeau 编译器使用的 EDG(爱迪生设计组)前端,它实现了export. 该关键字被某些人视为错误功能,并且大多数编译器都没有实现它。

  • 如果您想使用案例 2,将定义放入标题中是没有好处的,因为没有理由这样做:您只需为固定类型集显式实例化所需的函数和类。在第二种情况下,您使用模板来避免维护可能冗余代码的负担,并在某些情况下可以选择为某些类型引入特殊行为。

您的场景显然是第一种情况,因此您必须将定义放入标题中。

于 2009-06-16T23:27:10.257 回答
1

您似乎在 VehicleManager.h 中有复制和粘贴错误:

#ifndef MULTITHREADEDVECTOR_H
#define MULTITHREADEDVECTOR_H

这禁止包含定义类 Foo 的头文件。

于 2009-06-16T13:12:54.350 回答
1

在大多数情况下,您不能在 cpp 文件中编写模板实现。将模板实现移动到头文件中,以便编译器可以正确实例化它。

于 2009-06-16T13:13:28.187 回答
1

除了其他答案:

你也得防备get_container()。这种方法基本上是复制container_元素,因此必须加以保护。

template<class T>
vector<T> MultithreadedVector<T>::get_container() 
{
    return container_;
}
于 2009-06-16T13:15:34.233 回答
1

在某种程度上,模板是一种高级的、专门的宏。您实际上不能像您尝试做的那样单独编译模板定义。

对于大多数人来说,这意味着他们甚至不必费心将模板定义与声明分开。我有一位同事更进一步,也拒绝分离非模板定义和声明。

如果您想从声明中放入模板的定义,您确实有几个选择。

第一个选项是使用 C++“export”关键字。这个看似简单的解决方案的问题是没有人支持它。编译器编写者很难实现。

第二种选择是使用第三种类型的文件,通常标记为“.ipp”,用于声明。这里的诀窍是它仍然是一个必须是“#included”的文件,但作为一个单独的文件,你只需要将它包含在“.cpp”文件中。如果我在一个程序中的多个“.cpp”文件中#include 一个“.ipp”,我发现我的链接器不喜欢它,所以你必须选择一个作为包含器。

于 2009-06-16T13:55:57.787 回答