2016-03-04 21 views
12

Nie jestem pewien, czy jest to błąd kompilatora GCC lub zamierzonego zachowania noexcept.
Rozważmy następujący przykład:noexcept, dziedziczenie konstruktorów i nieprawidłowe użycie niekompletnego typu, który jest rzeczywiście kompletny

struct B { 
    B(int) noexcept { } 
    virtual void f() = 0; 
}; 

struct D: public B { 
    using B::B; 
    D() noexcept(noexcept(D{42})): B{42} { } 
    void f() override { } 
}; 

int main() { 
    B *b = new D{}; 
} 

Jeśli noexcept jest usuwany, kompiluje.
W każdym razie, jak to jest w tym przykładzie, mam ten błąd od v5.3.1 GCC:

test.cpp:8:31: error: invalid use of incomplete type ‘struct D’ 
    D() noexcept(noexcept(D{42})): B{42} { } 
          ^

O ile mi wiadomo, struct D nie jest niekompletny typ, ale dziedziczenie konstruktorzy są zaangażowane w rachunku i Wygląda na to, że kompilator faktycznie rozważa kompletność podstawowej struktury, niż .

Czy to zamierzone zachowanie, czy też jest to kodeks prawny?

Dla jasności:

  • here kompilacja udaje wykorzystaniem szczęk 3.7.1
  • here kompilacja nie używając GCC 5.3.0

Zobacz this link do the bugzilla dla kompilatora GCC dla dalszych szczegółów.
Obecnie błąd jest nadal niepotwierdzony. Zaktualizuję to pytanie tak szybko, jak to możliwe.

+0

Hmm, Clang 3.7.1 akceptuje ten kod. Założę się, że jest to błąd GCC. – thirtythreeforty

+0

Tak, dla mnie brzmi to znacznie bardziej jako błąd w kompilatorze GCC, ale może to być również błąd w klangu !! Nie jestem pewien, czy to prawidłowy kod, mimo że dla mnie wygląda dobrze. Pomoże w tym prawnik językowy. :-) – skypjack

+0

Dodałem lokalizację, na którą kompiluje się skarga, wraz z ostateczną wersją dla przyszłych pracowników Google (najnowszy stabilny GCC w tym piśmie). – thirtythreeforty

Odpowiedz

12

Twój kod jest legalny, mimo że GCC twierdzi inaczej. Zajmuje przestępstwa w tej zabawnej wyglądających deklaracji:

D() noexcept(noexcept(D{42})); 

Zewnętrzna noexcept jest noexcept specifier, stwierdzając, że D::D() jest noexcept tylko wtedy, gdy jej argument stałym wyrażenie true. Wewnętrzny noexcept jest noexcept operator, który sprawdza w czasie kompilacji, czy jego wyrażenie argumentu, które nie zostało faktycznie ocenione, nie zgłasza żadnych wyjątków. Ponieważ D::D(int) nie jest wyjątkiem (dziedziczone z B), powinno to być prawdą.

cppreference.com wyraźnie stwierdza, że ​​za pomocą operatora wewnątrz specyfikatora pozostawia (podkreślenie)

Operator noexcept przeprowadza kontrolę w czasie kompilacji, która zwraca prawdziwe jeśli ekspresja jest uznany nie rzucać żadnych wyjątki.

Może być używany w specyfikatorze noexcept szablonu funkcji, aby zadeklarować, że funkcja będzie generować wyjątki dla niektórych typów, ale nie dla innych.

Teraz klasa należy uznać kompletny w specyfikatorem noexcept powodu §9.2.2 normy (pogrubioną naciskiem dodano)

klasa jest uważane za w pełni określony typ elementu (3.9) (lub całkowite typu) na zamknięciu } do klasy-specyfikatora. wewnątrz członu specyfikacją klasy klasa jest uważany jako kompletne w jednostek funkcyjnych, domyślnych argumentów wykorzystaniem deklaracja s wprowadzające Dziedziczenie konstruktory (12,9), wyjątku specyfikacji s i brace- lub-equal-initializer s dla niestatycznych elementów danych (w tym takich rzeczy w klasach zagnieżdżonych). W przeciwnym razie jest on uznawany za niekompletny w ramach własnej specyfikacji klasy dla specyfikacji użytkownika.

§15.4.1 określa wyjątku specyfikacją jako następujące gramatyki:

wyjątku specyfikacji:

  • dynamicznie wyjątku specyfikacji

  • noexcept-specyfikacja

Więc GCC nie powinien odrzucić swój kod.

+0

Po tym pisaniu nie widzę biletu GCC dla tego konkretnego problemu. Może mógłbyś złożyć jeden? – thirtythreeforty

+0

Zamierzam to dodać. [Tutaj] (https://gc.gnu.org/bugzilla), prawda? – skypjack

+0

Myślę, że tak, tak! Możesz powrócić do tej odpowiedzi lub skopiować odpowiednie bity (głównie druga połowa). – thirtythreeforty