给出以下代码:
#include <iostream>
template <std::size_t N>
struct foo
{ static std::size_t value; };
template <>
std::size_t foo<0>::value = 0u;
template <size_t N>
std::size_t foo<N>::value = 1u + foo<N - 1u>::value;
int main()
{
std::cout
<< foo<3u>::value << ' '
<< foo<2u>::value << ' '
<< foo<1u>::value << ' '
<< foo<0u>::value << std::endl;
}
其中模板struct value
的静态成员foo
被递归初始化,我从g ++得到不同的输出:
3 2 1 0
从clang ++:
1 1 1 0
所以似乎g ++使用foo<N>::value
的初始化值递归地初始化foo<N-1u>::value
,其中clang ++对foo<N-1u>::value
使用零。
两个问题:
它没有具体说明。两个编译器都是对的。
以下是cppreference "initialization"的相关内容。
对于所有其他非本地静态和线程局部变量,将进行零初始化
因此,对于所有这些变量,程序加载时它们为零。然后:
完成所有静态初始化后,在以下情况下会发生非局部变量的动态初始化:
1)无序动态初始化,仅适用于(静态/线程局部)类模板静态数据成员和......未明确专门化的。
这些变量符合标准。然后它说:
对于所有其他动态初始化,这些静态变量的初始化是不确定的。
这意味着任何初始化序列都可以。两个编译器都是正确的。
为了避免这个问题,请使用constexpr
来强制进行“常量初始化”。
它是未指定的。
您正在使用一个构造,您可以在其中引用变量定义 - 可能有点类似于说int i = i-1
。在clang的情况下,它只是使用通用模板定义
template <std::size_t N>
struct foo
{ static std::size_t value; };//without specialization this will be ZERO initialized
因为它没有像普通模板类或函数那样看到'本身'(与gcc情况相反)。
总结一下:
1)合法
2)未指定
为了避免问题,请使用constexpr并专门化类模板。