繁体   English   中英

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

[英]g++ and clang++ different behaviour with recursive initialization of a static member

给出以下代码:

#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 foo的静态成员value的地方,我从g ++获得不同的输出:

3 2 1 0

从clang ++:

1 1 1 0

所以似乎g ++使用foo<N-1u>::value的初始化foo<N>::value递归初始化foo<N-1u>::value ,其中clang ++对foo<N-1u>::value使用零。

两个问题:

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

它没有具体说明。 两个编译器都是对的。

以下是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)未指定

为了避免问题,请使用并专门化类模板。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM