`constexpr`变量"用于它自己的初始化程序":Clang vs. GCC

时间:2017-10-11 12:21:06

标签: c++ compiler-errors c++17 constexpr

这个问题似乎与an existing one有关,但我不明白"便携式解决方法"在the answer there中提供(涉及const auto this_ = this;),而且我认为以下示例更容易理解。

我正在使用以下C ++ 17代码片段(live demo):

#include <iostream>

struct Test {
  const char* name_{nullptr};
  const Test* src_{nullptr};

  constexpr Test(const char* name) noexcept
    : name_{name}
  {}

  constexpr Test(const Test& src) noexcept
    : src_{&src}
  {
    name_ = src_->name_;
    src_ = nullptr;
  }
};

template<char c>
void print_constexpr_char() {
    std::cout << c << std::endl;
}

int main() {
  constexpr const char* in = "x";
  constexpr auto foo = Test{in};
  constexpr auto bar = Test{foo};
  std::cout << bar.name_ << std::endl;

  print_constexpr_char<bar.name_[0]>();

  return 0;
}

使用GCC 7.2进行编译失败,而Clang 5.0.0没有看到任何问题。 GCC错误基本上是

  

错误:&#39; bar&#39;的值不能用于常量表达式

     

注意:&#39; bar&#39;在其自己的初始化程序中使用

我意识到删除最后的print_constexpr_char使代码编译后更加困惑,尽管它仍然包含GCC过去抱怨的行constexpr auto bar = Test{foo};(&#34;在其自己的初始化程序中使用#34;。)

  1. 哪个编译器在这里是正确的?
  2. 如何理解GCC注释(如果不是错误)&#34;在其自己的初始化器中使用&#34;如果随后将结果用于常量表达式,那么会有害吗?
  3. 在将构造中的对象转换为可以存储在constexpr变量中的最终状态之前,是否有一种有效的方法/解决方法在constexpr构造函数中使用指针作为中间阶段?

1 个答案:

答案 0 :(得分:10)

GCC拒绝代码是正确的(但错误消息可能会使用一些工作)。除非该变量具有静态存储持续时间,否则不能在常量表达式中使用变量的地址。

foo不是静态的。如果你将它移到main之外,事情就会奏效。 Demo

下面标出的行是问题:

constexpr Test(const Test& src) noexcept
: src_{&src} <--- That

标准参考:( 强调我的)

[expr.const]

  

常量表达式是一个glvalue核心常量表达式,它引用一个允许的实体   常量表达式的结果(如下定义),或者值满足的prvalue核心常量表达式   以下约束:   
  
  (5.2) - 如果值是指针类型,它包含具有静态存储持续时间的对象的地址,   地址超过此类对象的结尾(8.7),函数的地址或空指针值