c++ - 如果表达式的求值需要对引用求值,为什么表达式不是 "core constant expression"?

标签 c++ c++11 c++17 language-lawyer constexpr

(这是对 this 问题的跟进。)

所以我想专门问一个问题来理解that answer中引用的标准语我收到了,我的确切问题在标题中。

老实说,甚至没有 cppreference我理解标准为什么这样说的原因。

但是,这是最小的示例:

#include <array>
int main() {
    auto arr = std::array<int,3>{{1,2,3}};
    constexpr auto size1 = arr.size(); // OK
    auto const& array = arr;
    constexpr auto size2 = array.size(); // does not compile
}

它没有编译错误(消息错误与 -std=11/14/17/2a 相同,因此两个极端的标记)

$ g++ -std=c++17 deleteme.cpp && ./a.out 
deleteme.cpp: In function ‘int main()’:
deleteme.cpp:6:39: error: the value of ‘array’ is not usable in a constant expression
    6 |     constexpr auto size2 = array.size(); // does not compile
      |                                       ^
deleteme.cpp:5:17: note: ‘array’ was not initialized with a constant expression
    5 |     auto const& array = arr;
      |                 ^~~~~

但如果我们删除 &,它编译.

另一方面,如果我只依赖纸条,上面写着 ‘array’ was not initialized with a constant expression ,我会假设以下编译

#include <array>
int main() {
    constexpr auto arr = std::array<int,3>{{1,2,3}};
    constexpr auto size1 = arr.size(); // OK
    constexpr auto& array = arr;
    constexpr auto size2 = array.size(); // does not compile
}

但它没有,编译器说(消息错误与 -std=11/14/17/2a 相同)

$ g++ -std=c++17 deleteme.cpp && ./a.out 
deleteme.cpp: In function ‘int main()’:
deleteme.cpp:5:29: error: ‘arr’ is not a constant expression
    5 |     constexpr auto& array = arr;
      |                             ^~~

这基本上意味着 arr不是“常量表达式”,即使它是 constexpr ,这至少在我看来是一个非常糟糕的措辞。

最佳答案

我相信这是因为 constant-expression rules允许我们使用 address-of 运算符,如 this answer 中所暗示的那样.例如,this is legal :

void f() {
    int i, j;
    constexpr bool b = &i == &j; // OK, b := false since i and j are distinct objects
}

允许在常量表达式中使用引用似乎无害:

void g() {
    int i, j;
    int& r = j;
    constexpr bool b = &i == &r; // OK, surely?
}

但是我们可以使引用的指称依赖于一个非常量变量,然后将那个非常量值偷偷带进常量求值中:

void h(bool a) {
    int i, j;
    int& r = a ? i : j;
    constexpr bool b = &i == &r; // oops, b := a
}

应该可以放松一下the prohibition on evaluating references禁止获取(或使用?)引用地址,但肯定需要付出一些努力才能确保新语言达到预期效果。

附录:论文P2280R1 "Using unknown references in constant expressions"打算打击使您的原始示例格式错误的标准语。它(还)没有详细说明允许的内容,但似乎不允许形成或比较指向“未知”对象的指针,这些对象是 constexpr 上下文外部引用的引用对象,因此 g() 将继续无效,更何况 h()

关于c++ - 如果表达式的求值需要对引用求值,为什么表达式不是 "core constant expression"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65239211/

相关文章:

c++ - 在 VC++ 中解决 hid.lib "unresolved external symbol"链接器错误

c++ - 0xC0000005 : Access violation after calling CopyMemory()

c++ - G++ 新的 ABI 问题

键和文件的 C++ 映射不起作用

c++ - std::variant 与里面的 std::nullptr_t 比较

c++ - 在 C++ 中读取多行输入

c++ - 将 null 分配给 QML 中 C++ 类型的 QObject* 属性时断言失败

c++ - 功能模板的部分属性在 GCC 中被静默忽略

c++ - 折叠表达式 vs 编译递归

c++ - 为什么取消引用指向 std::set 的提取节点的指针是未定义的行为?