模板专用化的不同编译器行为
Different compilers behavior for template specialization
我在尝试专用化模板时发现了不同的编译器行为。以下是说明该问题的最小代码:
#include <iostream>
template<typename A, typename B>
struct foo {
static const bool value = false;
};
template<typename B>
struct foo<int, B> {
static const bool value = !foo<B, B>::value;
};
int main() {
std::cout << foo<int, int>::value << std::endl;
return 0;
}
我有两个参数的通用模板和第一个int
类型参数的专用模板。使用 g++ 编译器时,我得到
main.cpp: In instantiation of 'const bool foo<int, int>::value':
main.cpp:10:30: recursively required from 'const bool foo<int, int>::value'
main.cpp:10:30: required from 'const bool foo<int, int>::value'
main.cpp:14:32: required from here
main.cpp:10:30: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
static const bool value = !foo<B, B>::value;
由于编译器使用value
专用版本,因此获得了无限递归。我得到
Error C2131 expression did not evaluate to a constant
Error C2065 'value': undeclared identifier
对于 MSVC。但是使用 clang 或 zapcc,代码编译时没有错误。原因是什么?在这种情况下,根据标准的正确行为是什么,还是行为未定义?
我不是语言律师,但这不应该编译。您正在尝试在编译时使用自身初始化值。我猜这是一个叮当虫。实际上,我不明白为什么GCC如果遇到一个循环,应该遵循这样的递归路径。
顺便说一下,MSVC告诉你(GodBolt):
<source>(14): note: see reference to class template instantiation 'foo<int,int>' being compiled
这是正确的收获。这一次,MSVC超越了其他编译器... :-P
编辑:@aschepler注意到即使没有模板,我们也会得到相同的行为(GodBolt):
struct bar { static const bool value = !bar::value; };
另一个编辑:似乎直到几年前,由于"语言律师的诡辩",这还是某种有效的代码。你看,标准曾经说过(第 6.6.2 节 [basic.start.static] 第 2 段):
具有静态存储持续时间的变量... 应为零初始化...在进行任何其他初始化之前。
Clang认为这意味着首先你对所有内容进行零初始化,然后考虑静态持续时间初始化 - 这意味着bar::value
在自己的显式初始化之前隐式decltype(bar::value) { 0 }
。这在 2026 年缺陷报告之后发生了变化。
指出这一点的功劳要归功于理查德·史密斯。
相关文章:
- .cpp和.h文件中的模板专用化声明
- C/C++编译器通常会删除重复的库吗
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- Win32编译器选项和内存分配
- 类模板部分专用化:编译器错误
- 模板专用化与编译器优化
- 模板专用化的不同编译器行为
- 模板函数专用化的内部编译器错误
- MSVC 编译器实例化函数模板的默认定义,即使存在专用化
- 使用类的特定模板专用化时的编译器警告
- G++:有哪些方法可以找出编译器选择了哪个模板专用化
- C++编译器忽略具有模板化类型的类专用化
- SFINAE:编译器不选择专用模板类
- 无法专用化函数模板编译器错误
- 为什么编译器在定义类似的模板专用化时不会出错?
- 在 Visual C++ 下使用模板专用化时编译器错误
- 无法引用专用静态成员变量:编译器错误
- 编译器选择了错误的模板函数专用化
- 如何使编译器使用正确的模板专用化
- 专用嵌套类的静态函数会导致编译器错误 C3855 (MSVC9)