忽略类模板的显式实例化?

时间:2015-11-08 20:18:24

标签: c++ c++11 instantiation explicit

我想检查extern关键字确实阻止了在翻译单元中生成类代码:

template<class> struct always_false : std::false_type {};

template <typename T> class A{
    static_assert(always_false<T>::value, "If this fires, 'A' is instantiated");
};

extern template class A<int>; //error: static assertion failed: If this fires, 'A' is instantiated|

int main(){
//    A<int> f;
}

如果这是我唯一的源文件,为什么前面的代码仍会从static_assert产生错误?据我明确使用extern所理解,这应该可以防止为类A<int>生成任何代码,并且链接器负责查找稍后的显式实例化定义(在翻译单元中,代码实际上已写入)以匹配A<int>的任何使用。

然而,似乎显式实例化声明正在此转换单元本身中生成代码,如编译错误所示。如果我评论extern template class A<int>一切正常。我使用的是GCC 4.9.2。但似乎clang 3.5.1也会抛出此错误。

或者这也会引发相同的断言错误:

template<class> struct always_false : std::false_type {};

template <typename T> class A{
public:
    void test() { static_assert(always_false<T>::value, "If this fires, 'test()' is instantiated"); }
};

extern template void A<int>::test();

int main(){
    A<int> a;
    a.test();
}

在这里,我希望成员函数A<int>::test()甚至不会被实例化,并再次等到链接之前发现&#34;&#34;函数的代码,但看起来代码是在同一个翻译单元中生成的。但是,如果我拿出static_assert

template <typename T> class A{
public:
    void test() { }
};

extern template void A<int>::test();

int main(){
    A<int> a;
    a.test();
}

然后我得到了我期待的错误,表明A<int>::test()没有实例化,并且存在链接器错误:

**undefined reference to `A<int>::test()'|**

如果static_assert从未实例化,为什么test()会抛出错误?

1 个答案:

答案 0 :(得分:3)

你的前提是错的。 extern template阻止了函数模板(包括类模板的成员函数)的目标代码生成,但它并没有阻止类主体的实例化。

编辑:要回答更新的问题:成员函数是在类中内联定义的,因此编译器仍然会实例化它,以便在必要时可以内联它。如果您将该功能定义为异常,则不会出现错误(通过godbolt尝试GCC 5.2.0)。

#include <type_traits>

template<class> struct always_false : std::false_type {};

template <typename T> class A{
public:
    void test();
};

template <typename T>
void A<T>::test() { static_assert(always_false<T>::value, "If this fires, 'test()' is instantiated"); }

extern template void A<int>::test();

int main(){
    A<int> a;
    a.test();
}