类模板构造函数模板的显式实例化定义是否合法?Clang与GCC分歧解析
构造函数模板的显式实例化合法性分析
背景:普通成员函数模板的显式实例化
先看如下类模板:
template <typename> struct S { template <typename T> void f(T) { /* ... */ } };
我们可以为S本身以及成员函数模板S::f提供显式实例化定义(或用extern template声明):
template struct S<int>; template void S<int>::f<int>(int);
构造函数模板的显式实例化争议
如果把普通成员函数模板替换为构造函数模板:
template <typename> struct S { template <typename T> S(T) { /* ... */ } };
此时不同编译器的行为出现分歧:
Clang认为可以为
S本身提供显式实例化,但无法单独实例化构造函数模板:template struct S<int>; // 合法 template S<int>::S<int>(int); // 编译错误Clang给出的错误信息:
error: out-of-line constructor for 'S' cannot have template arguments
template S::S (int);
^~~~~~GCC则接受上述两个显式实例化定义。
核心问题:该显式实例化是否合法?Clang的拒绝是否正确?
根据C++标准规定,构造函数模板的显式实例化语法有特殊要求:构造函数没有名字,因此在显式实例化时,不能像普通成员函数模板那样在限定名中显式指定模板实参(即S<int>::S<int>这种写法不符合语法规范)。
正确的构造函数模板显式实例化写法,应该通过函数签名推导模板实参,而非显式写出:
template S<int>::S(int);
此时编译器会根据参数类型int自动推导出构造函数模板的模板实参T=int。
而template S<int>::S<int>(int);这种写法违反了构造函数(模板)的命名规则,因此Clang的拒绝是符合C++标准的,GCC的行为属于对标准的扩展支持。
内容的提问来源于stack exchange,提问作者Vittorio Romeo
相关产品推荐
相关产品推荐

