C ++ 'da, eğer throw bir ifadeyse, türü nedir?


115

Bunu reddit için kısa sürelerimden birinde aldım:

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

Temel olarak yazar, C ++ 'da şunu belirtir:

throw "error"

bir ifadedir. Bu aslında hem ana metinde hem de dilbilgisinde C ++ Standardında oldukça açık bir şekilde ifade edilmiştir. Bununla birlikte, net olmayan şey (en azından benim için) ifadenin türü nedir? " void" Olduğunu tahmin ettim , ancak g ++ 4.4.0 ve Comeau ile biraz deneme yapmak şu kodu verdi:

    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
    }

Derleyicilerin // 1 ile bir problemi yoktu ama // 2'de kustular çünkü koşullu operatördeki türler farklı. Yani bir throwifadenin türü geçersiz görünmüyor.

Öyleyse nedir?

Cevap verirseniz, lütfen ifadelerinizi Standart'tan alıntılarla yedekleyin.


Bu, koşullu operatörün fırlatma ifadeleriyle nasıl başa çıktığı kadar fırlatma ifadesinin türü ile ilgili olmadığı ortaya çıktı - bugünden önce kesinlikle bilmediğim bir şey. Cevap veren herkese teşekkürler, ama özellikle David Thornley'e.

c++  throw 

10
+1 Harika soru. Ve bunu test etmenin akıllıca bir yolu.
Jeremy Powell

1
Bu bağlantı, türün, olması gerektiği gibi derleyici tarafından belirlendiğini oldukça açık bir şekilde ortaya koyuyor.
Draemon

Bağlantılı makale, baktığımdan beri güncellendiğini düşünüyorum ve eminim aslında durum böyledir. Ancak standartta bulamıyorum.

Ve belki de değil - çift d = "foo" at; G + = bir hatadır (Comeau ile test değil)

+1 Cevabı bilmek merak ediyorum.
AraK

Yanıtlar:


96

Standarda göre, 5.16 paragraf 2 birinci nokta, "İkinci veya üçüncü işlenen (ancak her ikisi de değil) bir fırlatma ifadesidir (15.1); sonuç diğerinin tipindedir ve bir r değeridir." Bu nedenle, koşullu operatör bir fırlatma ifadesinin ne tür olduğunu umursamaz, yalnızca diğer türü kullanır.

Aslında, 15.1, paragraf 1 açıkça "Bir fırlatma ifadesi geçersizdir" diyor.


9
Tamam - Sanırım bir kazananımız var.

Atma ifadesinin atama ifadesi olduğuna dikkat edin. Dolayısıyla, çoğu operatöre argüman olarak sözdizimi hatasıdırlar. Açıkçası, bunları parantez içinde gizleyebilirsiniz, ancak yok sayılmazlarsa (örneğin yerleşik operatörün ilk argümanı), bu bir tür hatasıdır.
AProgrammer

4
Beni asıl şaşırtan şey, bu davayı düşünmeleri ve makul bir şey gerçekleştirmeleri.
Omnifarious

31

"Bir fırlatma ifadesi void tipindedir"

ISO14882 Bölüm 15


Öyleyse hem g ++ hem de Comeau // 1 durumum için bir hata vermedikleri için ihmal mi?

2
@Neil, gerçekten değil, çünkü C ++ / 5.16 / 2'ye göre, koşullu operatörün ikinci ve üçüncü işlenenlerivoid
mloskot

13

[İfade ikinci 2] 'den (koşullu operatör ?:):

İkinci veya üçüncü işlenenin türü (muhtemelen geçerli nitelikte) geçersizse, ikinci ve üçüncü işlenenler üzerinde lvalue-rvalue, diziden işaretçiye ve işlevden işaretçiye standart dönüşümler gerçekleştirilir ve aşağıdakilerden biri geçerli olacaktır:

- İkinci veya üçüncü işlenen (ancak ikisi birden değil) bir atma ifadesidir; sonuç diğerinin tipindedir ve bir değerdir.

- İkinci ve üçüncü işlenenlerin her ikisi de void tipine sahiptir; sonuç void türündedir ve bir r değeridir. [Not: Bu, her iki işlenenin atma ifadesi olduğu durumu içerir. - son not]

Yani, //1ilk durumda //2seninleyken, "aşağıdakilerden biri geçerli olacaktır" diye ihlal ediyordun, çünkü bu durumda hiçbiri yapmaz.


3

Bir tür yazıcı olabilir sizin için tükürür :

template<typename T>
struct PrintType;

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

Temelde uygulama eksikliği PrintType, derleme hata raporunun şunu söylemesine neden olacaktır:

tanımsız şablonun örtük somutlaştırılması PrintType<void>

böylece throwifadelerin türünde olduğunu gerçekten doğrulayabiliriz void(ve evet, diğer yanıtlarda bahsedilen Standart alıntılar bunun uygulamaya özgü bir sonuç olmadığını doğrular - ancak gcc değerli bilgileri yazdırmakta zorlanır)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.