在尝试专门化模板时,我发现了不同的编译器行为。这是说明问题的最少代码:
#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,代码可以正确编译。是什么原因?在这种情况下,根据标准,正确的行为是什么?行为是否未定义?
我不是语言律师,但这不应该汇编。您正在尝试在编译时使用其自身初始化值。我猜这是一个clang错误。实际上,我不明白为什么GCC遇到循环时为什么要遵循这样的递归路径。
<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之后对此进行了更改。
指出这一点的功劳是理查德·史密斯(Richard Smith)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句