【问题标题】:how to initialize a constexpr reference如何初始化 constexpr 引用
【发布时间】:2015-04-21 06:47:02
【问题描述】:

我正在尝试初始化 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
}

但我收到编译时错误

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

删除const 会导致

错误:将对“int”类型的引用绑定到“const int”类型的值删除限定符

尽管我感觉constexpr 自动暗示const 用于变量声明。

所以我的问题是:

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

PS:我看到了几个与我相关的问题,例如 Which values can be assigned to a `constexpr` reference? ,但我认为它们没有解决我的问题。

【问题讨论】:

    标签: c++ c++11 reference constexpr


    【解决方案1】:
    1. constexpr 引用有用吗? (即,比 const 引用“更好”)

    它们保证在程序启动之前被初始化,而对 const 的引用可以在程序开始运行后的动态初始化期间被初始化。

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

    constexpr 引用必须绑定到全局变量,而不是局部变量(或更正式地说,它必须绑定到具有静态存储持续时间的东西)。

    引用在概念上等同于获取变量的地址,并且局部变量的地址不是常量(即使在main 中也只能调用一次,因此它的局部变量只能初始化一次)。

    【讨论】:

    • 它们需要绑定到具有静态存储持续时间的东西,可以是本地的static 或全局的。
    • constexpr 影响引用,而不是它绑定的类型,所以要绑定到 const int 你仍然需要 const int&amp;
    • @antred [basic.start.main]/3: "函数main不能在程序中使用。main的链接是实现定义的。一个定义@的程序987654329@ 已删除或将 main 声明为 inlinestaticconstexpr 格式错误。名称 main 未保留。"
    • @antred 我不是 C 专家,但快速浏览一下 N1570 并没有发现类似的限制。 5.1.2.2.3/1 程序终止确实说“如果 main 函数的返回类型是与 int 兼容的类型,则从 initial 调用返回到 main 函数等效于以main 函数返回的值作为参数调用exit 函数..." [强调添加]。这似乎意味着对 main 的 非初始调用是合规的。
    • @T.C. “可以是本地的static 或全局的” 或生命周期延长到静态存储持续时间的临时:static constexpr int const&amp; x = 42; 很好。这也是为什么 static constexpr auto x = {1,2}; 被 clang++ 接受,但 constexpr auto x = {1,2}; 不是(在块范围内)。 (这意味着即使是 OP 代码中的 static constexpr const int&amp; z = +x; 也是合法的。)
    【解决方案2】:

    所以问题是 constexpr 引用需要绑定到具有静态存储持续时间的对象,这在 draft C++11 standard: N3337 部分 5.19 中进行了介绍 [expr.const] (强调我的):

    引用常量表达式是一个左值 指定具有静态存储持续时间的对象或函数

    的核心常量表达式

    draft C++14 standard: N3936 改变了措辞:

    一个常量表达式要么是一个glvalue核心常量表达式,它的值引用一个静态对象 存储持续时间或函数,或 prvalue 核心常量表达式,其值为对象,其中,对于 该对象及其子对象:

    • 每个引用类型的非静态数据成员指的是一个具有静态存储持续时间的对象或一个 功能,以及
    • 如果对象或子对象是指针类型,它包含静态存储对象的地址 持续时间、此类对象末尾的地址 (5.7)、函数的地址或空指针 价值。

    所以像这样更改x 的声明会起作用:

    constexpr static int x{20};
    

    【讨论】:

      【解决方案3】:

      就像T.C. 所说,初始化器需要是一个具有静态存储持续时间的对象。

      N4140/§5.19/4 一个常量表达式要么是一个glvalue核心 常量表达式,其值引用静态对象 存储期限 [...]

      N4140/§7.1.5/9 对象声明中使用的 constexpr 说明符 将对象声明为 const。这样的对象应具有字面量类型 并且应该被初始化。 [...]否则,或者如果constexpr 说明符在引用声明中使用,每个完整表达式 出现在其初始化程序中的应该是一个常量表达式。

      在 N3337 中,措辞不同。

      【讨论】:

        猜你喜欢
        • 2011-12-23
        • 2012-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-18
        • 2019-12-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多