В С++, если throw является выражением, каков его тип?
Я взял это в одном из моих коротких набегов, чтобы reddit:
http://www.smallshire.org.uk/sufficientlysmall/2009/07/31/in-c-throw-is-an-expression/
В основном автор указывает, что в С++:
throw "error"
- выражение. Это на самом деле довольно четко прописано в стандарте С++, как в основном тексте, так и в грамматике. Однако, что не ясно (по крайней мере для меня), каков тип выражения? Я догадался, что "void
", но немного экспериментировать с g++ 4.4.0 и Comeau дал этот код:
void f() {
}
struct S {};
int main() {
int x = 1;
const char * p1 = x == 1 ? "foo" : throw S(); // 1
const char * p2 = x == 1 ? "foo" : f(); // 2
}
У компиляторов не было проблем с // 1, но barfed on//2, потому что типы в условном операторе различны. Таким образом, тип выражения throw
не кажется пустым.
Итак, что это такое?
Если вы ответите, пожалуйста, создайте резервные копии своих заявлений с кавычками из Стандарта.
Это оказалось не столько в вопросе типа выражения броска, сколько в том, как условный оператор имеет дело с выражениями выражений - что-то, что я, конечно, не сделал
знать о до сегодняшнего дня. Спасибо всем, кто ответил, но особенно Дэвиду Торнли.
Ответы
Ответ 1
В соответствии со стандартом 5.16 параграфа 2 первая точка: "Второй или третий операнд (но не оба) являются выражением throw (15.1), результат имеет тип другого и является rvalue". Поэтому условному оператору не важно, какой тип имеет выражение throw, но просто будет использовать другой тип.
Фактически, в параграфе 1.1.1 явно указано "Выражение-выражение типа void".
Ответ 2
"Выражение-выражение имеет тип void"
ISO14882 Раздел 15
Ответ 3
Из [expr.cond.2] (условный оператор ?:
):
Если либо второй, либо третий операнд имеют тип (возможно, cv-qualified) void, то значение lvalue-to-r, преобразование между массивами и указателями, а также стандартное преобразование между функциями и указателями на втором и втором третьи операнды и одно из следующего:
- второй или третий операнд (но не оба) - это выражение-бросок; результат имеет тип другого и является rvalue.
- как второй, так и третий операнды имеют тип void; результат имеет тип void и является rvalue. [Примечание: это относится к случаю, когда оба операнда являются выражениями throw. - конечная нота]
Итак, с //1
вы были в первом случае, с //2
, вы нарушали "одно из следующих условий", поскольку в этом случае ни один из них не выполняет.
Ответ 4
У вас может быть принтер типа выплюнуть его:
template<typename T>
struct PrintType;
int main()
{
PrintType<decltype(throw "error")> a;
}
В основном отсутствие реализации для PrintType
приведет к сообщению об ошибке компиляции:
неявное создание шаблона undefined PrintType<void>
поэтому мы можем фактически убедиться, что выражения throw
имеют тип void
(и да, стандартные кавычки, упомянутые в других ответах, подтверждают, что это не конкретный результат реализации, хотя gcc печатает ценную информацию )