如何初始化一个constexpr引用

29

我尝试使用constexpr引用进行初始化,但没有成功。我尝试了

#include <iostream>

constexpr int& f(int& x) // can define functions returning constexpr references
{
    return x;
}

int main()
{
    constexpr int x{20};
    constexpr const int& z = x; // error here
}

但是我遇到了编译时错误

错误:常量表达式变量“z”必须由常量表达式初始化

删除const会导致如下错误:

错误:将类型为“const int”的引用绑定到类型为“int”的值会丢失限定符

尽管我感觉在变量声明中使用constexpr会自动意味着使用const

所以我的问题是:

  1. constexpr引用有用吗?(即比const引用“更好”)
  2. 如果是,如何有效地定义它们?

附注:我看到了一些与我的问题相关的问题,例如哪些值可以分配给`constexpr`引用?,但我认为它们没有解决我的问题。

3个回答

31
  1. constexpr引用有用吗?(即,比const引用“更好”吗)

它们保证在程序启动之前被初始化,而对常量的引用可以在程序启动后进行动态初始化后初始化。

  1. 如果是的话,我该如何有效地定义它们?

constexpr 引用必须绑定到全局变量,而不是局部变量(或更正式地说,必须绑定到具有静态存储期的内容)。

引用在概念上等同于获取变量的地址,局部变量的地址不是一个常量(即使在main中,它只能被调用一次,所以它的局部变量只会被初始化一次)。


10
它们需要绑定到具有静态存储期的东西,可以是局部的static或全局的。 - T.C.
3
constexpr 影响的是引用而不是它所绑定的类型,因此要绑定到 const int ,仍然需要一个 const int& - Jonathan Wakely
6
函数main不应在程序内使用。 main的链接是实现定义的。 将main定义为已删除或将其声明为“内联”,“静态”或“constexpr”的程序是非法的。名称main没有其他保留意义。 - Casey
4
我不是 C 专家,但快速查看 N1570 并未发现类似的限制。5.1.2.2.3/1 程序终止说明:“如果 main 函数的返回类型与 int 兼容,则从 main 函数的初始调用返回等效于使用 main 函数返回的值作为参数调用 exit 函数...” [强调已添加]。这似乎意味着对 main非初始调用是符合规范的。 - Casey
4
可以是本地的 static 变量,也可以是全局变量,或者是生存期延长到静态存储期的临时变量:static constexpr int const& x = 42; 是可以的。这也是为什么 static constexpr auto x = {1,2}; 被 clang++ 接受,但在块作用域中 constexpr auto x = {1,2}; 不被接受的原因。(这意味着甚至 OP 代码中的 static constexpr const int& z = +x; 也是合法的。) - dyp
显示剩余6条评论

11

问题在于constexpr引用需要绑定到具有静态存储期的对象上,这在C++11标准草案N3337的第5.19 [expr.const]中已经涵盖(重点强调):

常量表达式是一个lvalue核心常量表达式,它指代具有静态存储期或函数的对象。

C++14标准草案N3936更改了措辞:

常数表达式可以是值引用具有静态存储期对象或函数的glvalue核心常量表达式,或者是其值为对象的prvalue核心常量表达式,在该对象及其子对象方面:

  • 每个非静态数据成员的引用类型都引用具有静态存储期的对象或函数
  • 如果对象或子对象是指针类型,则它包含具有静态存储期的对象的地址,超过此类对象的结尾(5.7)的地址、函数的地址或空指针值。

所以像这样改变x的声明将起作用:

constexpr static int x{20};

5

正如 T.C. 所说的那样,初始化项需要是具有静态存储期的对象。

N4140/§5.19/4 常量表达式指的是 glvalue 核心常量表达式,其值引用了具有静态存储期的对象[...]

N4140/§7.1.5/9 在对象声明中使用 constexpr 限定符将该对象声明为 const。这样的对象必须具有字面类型并且必须被初始化。否则,如果在引用声明中使用 constexpr 限定符,其初始化列表中出现的每个完整表达式都必须是一个常量表达式。

N3337 中的措辞不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接