В С++, если 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 печатает ценную информацию )