2011-08-05 40 views
2

我有一个模板化的容器对象。我正在尝试为float版本创建专门的构造函数。问题是,当编译器试图编译使用float版本的第二个对象时,我得到一个multiple definition of错误。g ++中的模板规范编译错误

注意:整个班级在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 
} 

任何想法?谢谢!

编辑正在编译的对象也将进入单独的共享对象,不确定是否与它有关。

+1

g ++ 4.0.1也很好。升级? –

+0

目前,我无法这样做,或者相信我会。我被锁定到该版本的这个应用程序。 – steveo225

+0

只是为了测试,我将代码复制到了一个有g ++ 4.1.1的盒子,并得到了相同的错误。 – steveo225

回答

4

专业化仍然必须遵循单一定义规则,就像任何其他非模板方法一样。将其标记为内联或在源文件中定义方法体(而不是标题)。

-4

你可以使用typeid

template <typename T> Container<T>::Container() { 
    if(typeid(T)==typeid(float)) { 
     // do something special 
    } 
    else { 
     // do default initialization 
    } 
} 

缺点:你不能使用初始化列表中为您的特殊情况。 编辑: 当我写这个答案时,我仍然认为错误是由编译器造成的,而不是由OP的代码(没有看太多)。然而,这种类型的方法是绝对有效的C++(请参阅下面的链接),如果模板确实无法在您的特定编译器中正常工作,则它是一个相当不错的解决方法,并且如果您一旦切换到编译器更好。

示范:example @ ideone

+0

这不就是不好的设计吗?因为该尝试抛弃了模板提供的所有可能性。 – tgmath

+0

这可能会导致编译错误 –

+0

@tgmath:我aggree,最常使用'typeid'的代码代表糟糕的设计。但在这种情况下,给'typeid'的参数是一个类型而不是一个对象,它并没有那么糟糕。当然,如果可能的话,你应该使用模板。 – smerlin

1
template <> Container<float>::Container() { 
    // do something special 
} 

是专业化的定义。甲专业化必须在每个编译单元中声明它用于:

template <> Container<float>::Container(); 

只有一个CU的限定。所以你的.h必须有声明,你必须找到一个足够的(可能是新的).cpp的定义。 (正如Mark B指出的那样,使内联专业化也是一种允许将定义放在需要的所有编译单元中的方法)。

1

这很棘手。问题是你的专业化不是 模板,而是一个实际的功能定义。并且由于它位于 标题中,所以在包含它两次时会得到多个定义。 是这样的:

template<> Container<float>::Container(); 
在头

,并在一个单一的源文件的执行。