clang здесь верен, старое поведение состояло в том, чтобы безоговорочно преобразовывать значение в prvalue , которое, похоже, все еще реализует gcc.
Это был предмет DR 1560 , который был исправлен разрешением DR 1550 . DR 1560 говорит:
glvalue, появляющийся как один операнд условного выражения в
который другой операнд является бросающим выражением, преобразуется в
prvalue, независимо от того, как используется условное выражение:
Если второй или третий операнд имеет тип void, то lvalue-to-rvalue (7.1 [conv.lval]), массив-указатель (7.2
[conv.array]) и стандартная функция-указатель (7.3 [conv.func])
преобразования выполняются на втором и третьем операндах, и один из
должно соблюдаться следующее:
- Второй или третий операнд (но не оба) является выражением броска (18.1 [кроме. Броска]); результат имеет тип
другой и является prvalue.
Это кажется неожиданным и неожиданным.
и DR 1550
изменили формулировку в [expr.cond] на то, что мы имеем сейчас:
Второй или третий операнд (но не оба) является (возможно, заключенным в скобки) бросающим выражением; результат имеет тип и значение категории другого. Условное выражение является битовым полем, если этот операнд является битовым полем.
Похоже, что gcc реализует старое поведение, в то время как clang реализует DR.
Это патч , который применил DR 1560 для лягушки . В него добавлен следующий тест:
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;
}
который на Годболте мы видим, что это не работает для gcc из-за:
error: lvalue required as left operand of assignment
4 | (b ? throw 0 : n) = (b ? n : throw 0) = 0;
|
У нас есть отчет об ошибке gcc для очень похожей проблемы со следующим сокращенным тестовым примером:
Я хотел устранить эту ошибку и предоставить более простой тестовый пример:
void blah(int&) {}
int main() {
int i{};
blah(true ? i : throw);
}
результат с gcc 6.0:
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);
~~~~~^~~~~~~~~~~~~