【发布时间】:2015-03-06 14:45:25
【问题描述】:
下面的sn-p编译
#include <iostream>
int& f() { static int i = 100; std::cout << i << '\n'; return i; }
int main()
{
int& r = f();
r = 101;
f();
}
并打印值 (live example)
100
101
现在,阅读 N4140 中的 §8.5.3/5,我可以看到它编译是因为要点 (5.1.1),即引用是左值引用,初始化表达式是左值和 @987654325 @ 与 int (或 int& - 我不确定我应该在这里使用哪一个)引用兼容。
要点 (5.1) 和 (5.1.1):
——如果引用是左值引用和初始化表达式
— is an lvalue (but is not a bit-field), and “cv1 T1” is reference-compatible with “cv2 T2,” or ...
现在假设我将声明int& r = f(); 中的左值引用更改为右值引用,即int&& r = f();。我知道代码不会编译,因为右值引用不会绑定到左值。但我很好奇的是,如何使用标准得出这个结论?
我会解释我的困难:
- 显然
int&& r = f();已被项目符号 (5.2) 所涵盖,因为该引用是一个右值引用。
要点(5.2):
— 否则,引用应为对 a 的左值引用 非易失性 const 类型(即 cv1 应为 const),或引用 应该是一个右值引用。
- 原则上,我会说 (5.2.1.1) 支持这种初始化,因为初始化程序是一个函数左值并且
int与int(或int&)的引用兼容。
要点 (5.2.1) 和 (5.2.1.1):
——如果初始化表达式
— is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or ...
编辑
我已经逐字包含了 N4140 (C++14) 中的项目符号点,它们等同于 N3337 (C++11) 中的类似项目符号点。
【问题讨论】:
-
f()不是函数左值。它是一个函数调用表达式,一个左值表达式,类型为int。见[expr.call]。 5.2.2.2 适用,然后 5.2.2.4 使其格式错误。 -
@dyp 但是什么是函数左值?我刚刚注意到标准没有定义这个术语。
-
它是值类别“左值”和类型some function type的表达式。一个例子是 id 表达式
f。例如。你可以写using ft = int&(); ft& lvalue_ref_to_function = f; -
我认为function lvalues出现在该段中的原因是没有函数类型的rvalue-expressions。例如。 [expr.static.cast]/1 表示表达式
static_cast<ft&&>(f)是一个左值,尽管目标类型有右值引用。 -
@dyp 您的最后一条评论非常棒,尽管我会说
ft& lvalue-ref_to_function = f;侵犯了要点 (5.2.1.1),因为此时左值必须是 const per (5.2) 和更多 @ 987654342@ 也为函数g编译返回一个右值引用。请参阅此处 (coliru.stacked-crooked.com/a/43a4c351a58ab24b)。
标签: c++ reference initialization language-lawyer c++14