constexpr 与 const 引用交互的奇怪行为

Let*_*_Be 4 c++ constexpr c++20

我用 clang 和 gcc(主干版本)测试了以下代码。有人可以解释为什么使用普通 X 结构的情况不起作用,而按值捕获和使用 const 引用的包装情况都可以正常工作。

struct X {
  constexpr X(const int &v) : x(v) {}
  constexpr int Get() const { return x; }
private:
  const int& x;
};

constexpr X f(const X& r) {
  return r;
}

struct Y {
  constexpr Y(const int &v) : x(v) {}
  constexpr int Get() const { return x; }
private:
  const int x;
};

constexpr Y f(const Y& r) {
  return r;
}

struct Wrap {
  constexpr Wrap(const int& v) : x(v) {}
  constexpr Y Get() const { return Y{x}; }
private:
  const int x;
};


int main() {
  constexpr const int x = 10;

  /* this does not work for some reason 
  constexpr X a(x);
  static_assert(f(a).Get() == 10, "This should work.");
  */

  // This works.
  constexpr Y b(x);
  static_assert(f(b).Get() == 10, "This should work.");

  // This also works.
  constexpr Wrap c(x);
  static_assert(f(c.Get()).Get() == 10, "This should work.");

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 8

你在这里违反的规则:

constexpr X a(x);
Run Code Online (Sandbox Code Playgroud)

是一个consetxpr指针或constexpr参考必须参考具有静态存储持续时间的对象-这是它的地址给其自身的唯一的方法是常量表达式。这是不是与本案x

但是一旦你做到了(这const是多余的):

static constexpr int x = 10;
Run Code Online (Sandbox Code Playgroud)

然后剩下的工作:

constexpr X a(x);
static_assert(f(a).Get() == 10, "This should work.");
Run Code Online (Sandbox Code Playgroud)

具体规则为[expr.const]/11

常量表达式可以是一个glvalue芯常量表达式指的是一个常量表达式的允许的结果(如下面所定义)的实体,或prvalue芯常量表达式,其值满足以下约束条件:

  • 如果值是类类型的对象,则每个引用类型的非静态数据成员都引用一个实体,该实体是常量表达式的允许结果,

[...]

如果实体是具有静态存储持续时间的对象,该对象不是临时对象,或者是值满足上述约束的临时对象,或者是非立即函数,则该实体是常量表达式允许结果


又见这些 答案矿井。我可能应该关闭所有这些作为其中之一的欺骗?