Почему в trernary operator не может использоваться список braced-init-list?
Мой компилятор - это последний VС++ 2013 RC.
int f(bool b)
{
return {}; // OK
return b ? 1 : { }; // C2059: syntax error : '{'
return b ? 1 : {0}; // C2059: syntax error : '{'
return b ? {1} : {0}; // C2059: syntax error : '{'
}
Почему в ternary-операторе оператор braced-init-list не может быть использован?
Является ли это поведение определенным как плохо сформированный стандартом С++ или просто ошибка компилятора VС++?
Ответы
Ответ 1
Ну, вот что говорится в стандартном списке (8.5.3.1):
Список инициализация можно использовать
- как инициализатор в определении переменной (8.5)
- как инициализатор в новом выражении (5.3.4)
- в операторе return (6.6.3)
- как аргумент функции (5.2.2)
- как индекс (5.2.1)
- в качестве аргумента для вызова конструктора (8.5, 5.2.3)
- как инициализатор для нестатического элемента данных (9.2)
- в mem-initializer (12.6.2)
- в правой части присваивания (5.17)
Так как это не упоминает условный оператор, я думаю, ваш компилятор прав. Также обратите внимание, что условный оператор ожидает выражения с обеих сторон от :
(5.16), и, насколько я понимаю, инициализатор скобок не является выражением.
Ответ 2
Это синтаксическая ошибка. Список braced-init-list не является выражением, и он не имеет типа или значения. Список braced-init-list доступен в разных местах в грамматике С++, а операнды условного выражения не являются одним из этих мест. Поэтому ваш код не может даже разобрать.
Если вы хотите сделать это:
struct T { ... };
T f(bool b)
{
return b ? {i,j,k} : {x,y};
}
вместо этого вы можете сделать это:
T f(bool b)
{
return b ? T{i,j,k} : T{x,y};
}
и я верю, хотя для этого требуется конструктор перемещения, он не будет использовать его, и RVO будет входить.
В качестве альтернативы вы могли бы, конечно, сделать следующее:
T f(bool b)
{
if (b)
return {i,j,k};
else
return {x,y};
}
чтобы получить все преимущества инициализации списка.