我有一个模板化的容器对象。我正在尝试为float
版本创建一个专门的构造函数。问题是,当编译器尝试编译使用float
版本的第二个对象时,我收到multiple definition of
错误。
注意: h
文件中的整个班级。该文件包含一个定义(#ifndef
,#define
和#endif
)。 g ++版本3.4.6。这与其他编译器编译良好,例如英特尔的icc。
代码类似于以下内容:
template <typename T>
class Container {
public:
Container();
virtual ~Container() {}
private:
std::vector<T> data;
// other members
};
template <> Container<float>::Container() {
// do something special
}
template <typename T> Container<T>::Container() {
// do default initialization
}
有什么想法吗?谢谢!
编辑正在编译的对象也会进入单独的共享对象,不确定是否与它有关。
答案 0 :(得分:4)
专业化仍然必须像任何其他非模板方法一样遵守单一定义规则。将其标记为内联或在源文件(而不是标题)中定义方法体。
答案 1 :(得分:1)
template <> Container<float>::Container() {
// do something special
}
是专业化的定义。必须在使用的每个编译单元中声明专门化:
template <> Container<float>::Container();
并在CU的仅一个中定义。所以你的.h
必须有声明,你必须为定义找到一个足够的(可能是新的).cpp
。 (正如Mark B指出的那样,使内联专业化也是一种允许将定义放在需要的所有编译单元中的方法。)
答案 2 :(得分:1)
这很棘手。问题是你的专业化不是 模板,但实际的功能定义。因为它在一个 标题,当您包含两次时,您会得到多个定义。 类似的东西:
template<> Container<float>::Container();
标题中的,以及单个源文件中的实现。
答案 3 :(得分:-4)
您可以使用typeid
:
template <typename T> Container<T>::Container() {
if(typeid(T)==typeid(float)) {
// do something special
}
else {
// do default initialization
}
}
缺点:您无法使用初始化列表来处理您的特殊情况。 编辑: 当我写这个答案时,我仍然认为错误是由编译器引起的,而不是由OP的代码引起的(没有那么多看)。然而,这种typeid方法是绝对有效的C ++(参见下面的链接),如果模板确实无法与您的特定编译器一起正常工作,它是一个非常好的解决方法,并且如果有一天你可以切换到模板解决方案,它很容易被替换为模板解决方案更好的编译器。