2016-08-04 18 views
20

Badanie o "specyfikatorze noexcept (i operatorze)", napisałem prosty kod. I jestem zaskoczony, że ten kawałek kodu:Jak działa system typu specyfikatora wyjątków C++ 17?

void asdf() noexcept {} 
int main() 
{ 
    auto f = asdf; 
    std::cout << std::boolalpha << noexcept(f()) << std::endl; 
} 

drukuje false, nawet funkcja „asdf” jest noexcept określonym.

Poszukując dlaczego to tajemnicze zjawisko dzieje się, znalazłem "typ specyfikatora typu systemu C++ 17" - P0012R1.

Zgodnie z tą (zaakceptowaną) propozycją, ponieważ C++ 17; jako noexcept jest częścią typu funkcji, czy powyższy kod wydrukuje true?

I jeszcze jedno, w this pytanie w jednym wierszu:

std::function<void() noexcept> f 

noexcept określające wydaje ignorowane w C++ 14 lub 11. Będzie to działać zgodnie z przeznaczeniem kod w C++ 17?

+0

g ++ zwraca 'true' dla' noexcept (f()) 'bez' -std = C++ 1z' ​​(ale clang zwraca 'false'). – Holt

+0

Dla dodatkowej zabawy zmień 'auto f = asdf;' na 'void (* f)() noexcept = asdf;'. Teraz GCC wypisze 'false' podczas gdy clang drukuje' true'. – hvd

+0

@Holt Dzięki za informację. Używam MSVC (zwraca 'false'). Czym różniłyby się od nich? Czy to błąd g ++ lub C++ 14 lub wcześniejszego standardu nie określił niczego w systemie typu "noexcept"? – Gear

Odpowiedz

11

Zgodnie z tą (zaakceptowaną) propozycją, ponieważ C++ 17; ponieważ noexcept jest częścią typu funkcji, czy powyższy kod wydrukuje true?

Tak.

Rodzaj f będzie wnioskować do void(*)() noexcept ponieważ funkcja konwersji do wskaźnika stosowane do asdf zachowa własność noexcept. Wywołanie funkcji o wskaźniku funkcji noexcept nie może z pewnością rzucić wyjątku, chyba że jedno z jego podwyrażeń ma miejsce.

Dokładne brzmienie, patrz [expr.unary.noexcept]/3 i [expect.spec]/13. Zauważ, że nowe sformułowanie w ostatnim akapicie z projektu C++ 17 pochodzi z P0012R1, który jest powiązany w OP.

Wynik operatora noexcept jest true jeśli zestaw potencjalnych wyjątkiem tego wyrażenia ([except.spec]) jest pusta, a false inaczej.

...

  • e Jeżeli jest to wywołanie funkcji ([expr.call]):
    • Jeśli jego przyrostek ekspresja to (być może w nawiasach) ID ekspresja ([expr.prim.id]), dostęp do elementu klasy ([expr.ref]) lub operacja wskaźnik-do-członka ([expr.mptr.oper]), którego jest wyrażenie o numerze identyfikacyjnymS jest zbiorem typów w specyfikacji wyjątku jednostki wybranej przez zawarte id-expression (po przeciążeniu, jeśli dotyczy). ...

więc zbiór potencjalnych wyjątkami f() jest taki sam jak zbiór typów w specyfikacji wyjątkiem f, który jest pusty, ponieważ f deklaruje noexcept.

Przejdźmy do drugiego pytania:

noexcept określające wydaje ignorowane w C++ 14 lub 11. To będzie działać zgodnie z przeznaczeniem kod w C++ 17?

Twoje pytanie brzmi: czy std::function<void() noexcept> odmówi posiadania funkcji, która może generować wyjątki?

Powiedziałbym, że jest to niejasne: . W obecnym brzmieniu normy, std::function<void() noexcept> nie jest faktycznie zdefiniowany, tak jak std::function<double(float) const> is not defined. Nie było to oczywiście problemu w C++ 14, ponieważ noexcept nie był uważany za część typu funkcji.

Czy std::function<void() noexcept> po prostu przerwie C++ 17? To jest dla mnie niepewne. Rzućmy okiem na obecne sformułowanie, aby odgadnąć, co to zachowanie powinno "być".

standard wymaga argumentu konstruktora std::function<R(ArgTypes..)> być „lwartości-niepokryta” typów argumentów ArgTypes... i rodzaju powrotu R, które means:

wywoływalnym typu ([func.def]) F jest Lvalue-Callable dla typów argumentów ArgTypes i typu zwrotu R, jeśli wyrażenie INVOKE(declval<F&>(), declval<ArgTypes>()..., R), uważane za nieoceniony operand (Clause [wyrażenie]), jest dobrze sformułowane ([func.require]).

Być może powinien istnieć dodatkowy wymóg, że jeśli typ funkcji to noexcept, wówczas noexcept(INVOKE(...)) musi również być prawdziwe. Niemniej jednak sformułowanie to nie występuje w obecnym projekcie.

W P0012R1, nie jest komentarz, że:

Jest kwestią otwartą, jak propagować "noexcept" przez std::function.

Domyślam się, że oznacza to, że nie jest jasne, w jaki sposób można wdrożyć std::function, jeśli nałożono to dodatkowe wymaganie. Mam nadzieję, że ktoś inny może podać więcej szczegółów.

+1

Oczywiście potrzebujemy 'std :: function_moveonly' i' std :: function_noexceptonly' oraz 'std :: function_moveonly_noexceptonly'. Ale co z 'std :: function_mutablecall'? To może stać się nieporządne. – Yakk