C++ 条件表达式在其他类型为 throw 表达式时删除引用

The*_*Pen 5 c++ reference rvalue lvalue

我有一个引用T*:的函数void f(T *&t);。当我使用带有 throw, 的条件表达式调用它时f(t == nullptr ? throw "nullptr" : t),程序无法编译:

error: cannot bind non-const lvalue reference of type 'T*&' to an rvalue of type 'T*'
note:   initializing argument 1 of 'f(T*&)'
Run Code Online (Sandbox Code Playgroud)

然而,用编译替换上面的调用f(t)就可以了。

这是为什么?整个表达式应与非抛出操作数具有相同的类型: https: //en.cppreference.com/w/cpp/language/operator_other。从链接中,Either E2 or E3 (but not both) is a (possibly parenthesized) throw-expression. The result of the conditional operator has the type and the value category of the other expression.

可重现的示例: https: //godbolt.org/z/9MW1Kevxz

#include <iostream>
using namespace std;

struct T {
  int i;  
};

void f(T*& t) { 
    t->i = 2; 
}

int main()
{
    T *t = new T{5};
    f(t == nullptr ? throw "hi" : t);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在 x86-64 上使用 gcc 9.4 失败。

Yks*_*nen 7

这是CWG 1550 *。C++ 标准过去要求三元运算符的结果是另一个(非throw)操作数的类型,但值类别始终是纯右值。最终这一点发生了改变,现在保留了另一个操作数的值类别,但似乎 GCC 仅在版本 10 及更高版本中实现了更改(请在 godbolt 中在线查看)。

*从技术上讲,该问题已在CWG 1560中报告,但两者均在 CWG 1550 下得到解决,这就是显示差异的地方。