g ++和clang ++的不同行为与静态成员的递归初始化

max*_*x66 31 c++ recursion templates static-members language-lawyer

给出以下代码:

#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;
 }
Run Code Online (Sandbox Code Playgroud)

在递归地初始化value模板结构的静态成员的地方foo,我从g ++得到了不同的输出:

3 2 1 0
Run Code Online (Sandbox Code Playgroud)

和从c ++++:

1 1 1 0
Run Code Online (Sandbox Code Playgroud)

看来g ++ foo<N>::value使用foo<N-1u>::valueclang ++对0使用零的初始化值来递归初始化foo<N-1u>::value

两个问题:

  1. 是前面的代码合法还是某种程度上的未定义行为?
  2. 如果前面的代码是合法的,谁是对的:g ++或clang ++?

Mic*_*ler 26

未指定。两种编译器都是正确的。

这是来自cppreference“ initialization”的相关部分。

静态初始化

对于所有其他非局部静态变量和线程局部变量,初始化为零

因此,对于所有这些变量,在程序加载时它们均为零。然后:

动态初始化

在完成所有静态初始化之后,在以下情况下会发生非局部变量的动态初始化:

1)无序动态初始化,仅适用于未明确专门化的(静态/线程本地)类模板静态数据成员和...。

这些变量符合条件。然后它说:

相对于所有其他动态初始化,此类静态变量的初始化不确定地排序。

这意味着任何初始化顺序都可以。两种编译器都是正确的。

为避免此问题,请改用constexpr“恒定初始化”。