C++11中GCC与Clang对内部链接静态变量作非类型模板形参的差异
C++11中引用型非类型模板参数绑定静态全局变量的编译器差异问题
在C++17之前,GCC无法将引用类型的非类型模板形参绑定到静态全局变量,但Clang和MSVC支持该操作。
示例代码:
#include <iostream> #include <string> template <std::string& N> void printString() { std::cout << N << std::endl; } std::string a; static std::string b; template void printString<a>(); template void printString<b>(); // GCC在C++11下编译失败 int main() { }
在C++11标准下,Clang可成功编译上述代码,但GCC实例化带内部链接的静态变量b时会报错,错误信息如下:
<source>:14:27: error: the value of 'b' is not usable in a constant expression 14 | template void printString<b>(); | ^ <source>:11:20: note: 'b' was not declared 'constexpr' 11 | static std::string b; | ^ ASM generation compiler returned: 1 <source>:14:27: error: the value of 'b' is not usable in a constant expression 14 | template void printString<b>(); | ^ <source>:11:20: note: 'b' was not declared 'constexpr' 11 | static std::string b; | ^ Execution build compiler returned: 1
(注:GCC在C++17标准下可成功编译该代码)
问题解答
该现象是C++标准规则演进与编译器实现差异共同导致的:
标准规则的版本差异
- 在C11/C14标准中,引用类型的非类型模板参数的实参必须满足:要么是具有外部链接的对象,要么是
constexpr修饰的内部链接对象。示例中的static std::string b是内部链接且非constexpr,不符合C++11的要求。 - C++17标准修改了这一规则,允许引用型非类型模板参数绑定到具有内部链接的对象,只要该对象在模板实例化的作用域中可见且被odr-used。
- 在C11/C14标准中,引用类型的非类型模板参数的实参必须满足:要么是具有外部链接的对象,要么是
编译器实现的差异
- GCC在C11/C14模式下严格遵循当时的标准要求,因此拒绝编译绑定非
constexpr内部链接对象的模板实例化。 - Clang和MSVC在C11模式下对规则进行了宽松解读,或者提前实现了C17的新规则,因此允许这种绑定操作。
- GCC在C11/C14模式下严格遵循当时的标准要求,因此拒绝编译绑定非
内容的提问来源于stack exchange,提问作者zturn
相关产品推荐
相关产品推荐

