Eu tenho uma função que faz referência a a T*
: void f(T *&t);
. Quando eu o chamo com uma expressão condicional com throw, f(t == nullptr ? throw "nullptr" : t)
o programa falha ao compilar:
error: cannot bind non-const lvalue reference of type 'T*&' to an rvalue of type 'T*'
note: initializing argument 1 of 'f(T*&)'
No entanto, substituir a chamada acima por f(t)
compila perfeitamente.
Por que é que? A expressão inteira deve ter o mesmo tipo que o operando não lançado: https://en.cppreference.com/w/cpp/language/operator_other . Do link,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.
Exemplo reproduzível: 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;
}
Falha com gcc 9.4 em x86-64.
Este é o CWG 1550 * . O padrão C++ costumava exigir que o resultado do operador ternário fosse do tipo do outro (não
throw
) operando, mas a categoria de valor sempre era prvalue. Isso foi alterado eventualmente e a categoria de valor do outro operando agora é mantida, mas parece que o GCC só implementou a mudança na versão 10 e superior ( veja online em godbolt ).*tecnicamente, o problema foi relatado no CWG 1560 , mas ambos foram resolvidos no CWG 1550 e é aqui que a diferença é mostrada.