链接模板对象文件 - 与clang和gcc的不同行为

时间:2015-12-15 08:26:10

标签: c++ templates gcc linker clang

关于gcc和clang之间的不同行为存在很多问题。但是我还没找到解决问题的方法。

我使用模板,我想传播类的定义和实现。我读了很多(很多)我知道不同的可能性。我选择了具体的声明,我想支持哪些模板。用:

   template class Temp<char>;
   template class Temp<double>;

如果我将这些行放在template.cc文件的末尾,我选择支持哪些模板实际上有效。但是使用gcc我也可以在头文件中写它。 Clang不支持它,我得到链接错误。

但为什么呢?在头文件中声明使用的模板有什么问题???

这是我的玩具示例:

template.hh

#pragma once
#include <iostream>

template<typename T>
class Temp
{
public:
    Temp(T data);
    virtual ~Temp (){};
    void print();

private:
    T data_;
};

//Only gcc can support this
//template class Temp<char>;
//template class Temp<double> 

template.cc

#include "template.hh"                                                                                           

template<typename T>
Temp<T>::Temp(T data): data_(data)
{
}

template<typename T>
void Temp<T>::print()
{
    std::cout << data_ << " " << sizeof(data_) << std::endl;
}

//Delete those, if it is used in header
template class Temp<char>;
template class Temp<double>;

test.cc

#include "template.hh"

int main(int argc, char *argv[])
{
    Temp<char> temp = Temp<char>('c');
    temp.print();

    Temp<double> temp2 = Temp<double>(1.0);
    temp2.print();
    return 0;
}

期望的输出:

c  1
1  8

2 个答案:

答案 0 :(得分:3)

显式模板实例化属于“.cc”实现文件,而不是标题。如果要在标题中声明它,可以使用extern

执行此操作
extern template class Temp<char>;
extern template class Temp<double>;

这将避免使用Clang可能遇到的乘法定义符号。

可能GCC支持头文件中的显式实例化,但这并不意味着它是正确的C ++,只是说GCC在这种情况下是自由的。不要依赖它。

答案 1 :(得分:2)

函数模板的显式实例化是一个定义。类模板的显式实例化是实例化类模板的所有[非模板]成员函数的简写。在C ++中具有多个实体定义会导致违反ODR规则(一个定义规则)。违反ODR规则不需要诊断。

因此,模板的显式实例化属于&#34; .cc&#34;文件。如果您希望声明模板将在某个翻译单元中显式实例化,您可以使用extern模板声明,例如:

template <typename> void f();
template <typename> class F { /*...*/ };

extern template void f<int>();
extern template class F<int>();

extern模板声明允许在标头中定义模板,但禁止隐式实例化。相反,extern模板声明承诺将有一个翻译单元提供显式实例化。

相关问题