У C ++, якщо кидок - це вираз, який його тип?


115

Я взяв це в одному з моїх коротких наборів до reddit:

http://www.smallshire.org.uk/sufficsmall/2009/07/31/in-c-throw-is-an-expression/

В основному автор зазначає, що в C ++:

throw "error"

є виразом. Це насправді досить чітко прописано в стандарті C ++, як в основному тексті, так і в граматиці. Однак, що незрозуміло (мені щонайменше) - це тип виразу? Я здогадався " void", але трохи експериментуючи з g ++ 4.4.0 і Комо дав цей код:

    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, але зафіксували // 2, оскільки типи в умовному операторі різні. Тож тип throwвиразу не видається нікчемним.

Так що це?

Якщо ви дасте відповідь, будь ласка, підкріпіть свої заяви цитатами зі стандарту.


Це виявилося не стільки щодо типу виразу викидання, скільки того, як умовний оператор має справу з виразами кидка - те, про що, звичайно, не знав раніше. Дякую всім, хто відповів, але особливо Девіду Торнлі.

c++  throw 

10
+1 Дивовижне запитання. І розумний спосіб її тестування.
Джеремі Пауелл

1
Здається, це посилання дає зрозуміти, що тип визначається компілятором таким, яким він повинен бути.
Draemon

Зв'язана стаття, я думаю, була оновлена ​​з моменту її перегляду, і я впевнена, що це насправді так. Однак я не можу знайти його в стандарті.

А може і ні - подвійний d = кинути "foo"; помилка з G + = (б не протестували його з комі)

+1 Мені цікаво знати відповідь.
AraK

Відповіді:


96

Відповідно до стандарту пункту 2 пункту 2 статті 5.16, "Другий або третій операнд (але не обидва) - це вираз кидання (15.1); результат має тип іншого та є ревальваційним значенням". Тому умовному оператору не байдуже, який тип є виразним кидком, а просто використовуватиме інший тип.

Насправді в пункті 1 пункту 1 статті 15 прямо написано "Вираз кидка є недійсним".


9
Гаразд - я думаю, що у нас є переможець.

Зауважте, що вираз-кидок - це призначення-вираз. Отже, вони є синтаксичною помилкою як аргументом більшості операторів. Очевидно, ви можете їх приховати в дужках, але якщо вони не ігноруються (наприклад, перший аргумент вбудованого оператора), це помилка типу.
AProgrammer

4
Що мене справді дивує, це те, що вони подумали про цю справу і зробили щось розумне.
всезначний

31

"Вираз кидка є недійсним"

ISO14882 Розділ 15


Тоді і g ++, і Comeau відмовляються не вводити помилки для мого // 1 випадку?

2
@Neil, не зовсім тому, що відповідно до C ++ / 5.16 / 2, другий та третій операнди умовного оператора можуть мати типvoid
mloskot

13

З [expr.cond.2] (умовний оператор ?:):

Якщо або другий, або третій операнд має тип (можливо, cv-кваліфікований) void, тоді стандартні перетворення lvalue-to-rvalue, array-to-pointer та function-to-pointer виконуються на другому та третьому операндах, і має бути проведено одне з наступних дій:

- Другий або третій операнд (але не обидва) - це вираз-кидок; результат є типом іншого та є ревальваційним.

- І другий, і третій операнди мають тип void; результат має тип void і є оцінкою. [Примітка. Це включає випадок, коли обидва операнди є виразами кидків. - кінцева примітка]

Отже, якщо //1ви були в першому випадку, //2ви порушували "один із наступних дій", оскільки жоден з них не робить у цьому випадку.


3

У вас може бути типовий принтер, який його виплюне :

template<typename T>
struct PrintType;

int main()
{
    PrintType<decltype(throw "error")> a; 
}

В основному, відсутність реалізації для PrintTypeцього призведе до того, що звіт про помилку компіляції скаже:

неявна інстанція невизначеного шаблону PrintType<void>

тому ми можемо фактично перевірити, що throwвирази мають тип void(і так, стандартні цитати, згадані в інших відповідях, підтверджують, що це не результат конкретного впровадження - хоча gcc важко друкує цінну інформацію)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.