C++未完整类型模板变量的编译兼容性与语法合规性问询
C++模板静态成员与extern特化的合规性问题
场景1:类静态成员与模板静态成员的decltype使用
struct foo; struct bar { static foo mem; template <typename> static foo tpl_mem; }; using mem_t = decltype(bar::mem); // (1) using tpl_mem_t = decltype(bar::tpl_mem<int>); // (2)
此处static仅用于成员声明而非定义,按C++标准,在decltype的未求值上下文中可以使用这些未定义的成员。但MSVC(v19.37)编译(2)时报错"undefined struct foo",却能正常编译(1);GCC 13、Clang 16、ICX 2023.2均可正常编译两个别名。
场景2:全局extern变量与模板变量的decltype使用
struct foo; extern foo var; template <typename> extern foo tpl_var; using var_t = decltype(var); using tpl_var_t = decltype(tpl_var<int>);
这段代码所有测试编译器(包括MSVC)都能正常编译。
场景3:模板变量的显式特化与extern
添加如下显式特化代码后:
template <> extern foo tpl_var<double>; // (3)
MSVC仍报错"undefined struct foo",GCC报错"explicit template specialization cannot have a storage class",而Clang和ICX可正常编译。
更新补充:偏特化中的extern
对于如下偏特化代码:
template <typename T> extern foo tpl_var<std::vector<T>>;
除MSVC外,其他编译器(包括GCC)均可正常编译。
问题与解答
1. 第一段和第二段代码(不含特化)及相关假设是否正确?
你的假设完全正确。依据C++标准:
- 在未求值上下文(如
decltype的操作数)中,仅需要类型的声明(无需完整定义)即可使用。foo作为不完全类型,仅用于decltype获取类型,不需要完整定义; - 类静态成员声明、全局
extern变量声明、模板变量的extern声明均为合法声明,未定义状态下在未求值上下文中使用符合标准要求。
MSVC对场景1中(2)的报错属于编译器实现缺陷,不符合标准规定。
2. 显式特化中能否使用extern?GCC的判断是否正确?
根据C++标准,显式模板特化不允许带有存储类说明符,GCC的判断是正确的:
- 标准明确规定,显式特化的声明语法中不能出现
extern这类存储类关键字; - 偏特化不属于显式特化范畴,因此偏特化中使用
extern是合规的,这也解释了GCC允许偏特化带extern但禁止显式特化的行为; - Clang和ICX允许显式特化带
extern属于编译器扩展,不符合标准要求。
内容的提问来源于stack exchange,提问作者rm -rf
相关产品推荐
相关产品推荐

