Nat*_*ell 4 c++ g++ conditional-operator language-lawyer value-categories
请考虑以下代码:
int x;
int& f() {
return x ? x : throw 0;
}
Run Code Online (Sandbox Code Playgroud)
随着gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
我得到以下编译错误:
cannot bind non-const lvalue reference of type ‘int&’ to an rvalue of type ‘int’
Run Code Online (Sandbox Code Playgroud)
请注意,这在clang中编译得很好.以下是(我相信的)标准中的相关陈述:
N4659 [8.16.2.1](条件运算符):
第二个或第三个操作数(但不是两个)是一个(可能带括号的)throw-expression(8.17); 结果是另一个的类型和值类别.
据我所知,x
是一个左值,所以在我看来clang
是对的.我错了吗?
clang在这里是正确的,旧的行为是无条件地将值转换为它看起来像gcc仍然实现的prvalue.
这是DR 1560的主题,由DR 1550的分辨率确定.DR 1560说:
无论条件表达式如何使用,glvalue作为条件表达式的一个操作数出现,其中另一个操作数是throw-expression,它将转换为prvalue:
如果第二个或第三个操作数的类型为void,则是左值到右值(7.1 [conv.lval]),数组到指针(7.2 [conv.array])和函数到指针(7.3) [conv.func])对第二个和第三个操作数执行标准转换,并且以下之一应该成立:
- 第二个或第三个操作数(但不是两个)是一个throw-expression(18.1 [except.throw]); 结果是另一个的类型,是一个prvalue.
这似乎是无偿和令人惊讶的.
并将[expr.cond]中DR 1550
的措辞改为现在的内容:
第二个或第三个操作数(但不是两个)是一个(可能带括号的)throw-expression; 结果是另一个的类型和值类别.如果该操作数是位字段,则条件表达式是位字段.
因此,当clang正在实施DR时,gcc似乎正在实现旧行为.
这是将DR 1560应用于clang的补丁.它增加了以下测试:
namespace DR1560 { // dr1560: 3.5
void f(bool b, int n) {
(b ? throw 0 : n) = (b ? n : throw 0) = 0;
}
class X { X(const X&); };
const X &get();
const X &x = true ? get() : throw 0;
}
Run Code Online (Sandbox Code Playgroud)
这对godbolt我们可以看到失败gcc的原因是:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
Run Code Online (Sandbox Code Playgroud)
我们有一个非常类似的问题的gcc 错误报告,其中包含以下简化的测试用例:
我想突破这个bug并提供一个更简单的测试用例:
Run Code Online (Sandbox Code Playgroud)void blah(int&) {} int main() { int i{}; blah(true ? i : throw); }
结果与gcc 6.0:
Run Code Online (Sandbox Code Playgroud)prog.cc: In function 'int main()': prog.cc:6:15: error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int' blah(true ? i : throw 0); ~~~~~^~~~~~~~~~~~~
归档时间: |
|
查看次数: |
151 次 |
最近记录: |