2016-02-02 11 views
8

Oggi stavo giocando con i modelli per vedere se potevo ottenere dal compilatore di dedurre il tipo di una classe esterna da una delle sue classi interne. Non ho trovato la mia soluzione (che sospetto sia impossibile), ma mentre provavo a correggere un errore mi sono imbattuto in un comportamento molto strano che ho ridotto al seguente frammento.È questo codice assurdo che compila bene un bug sia in Clang che in GCC?

struct A 
{ 
    struct B{}; 

    template <typename T> 
    struct EverythingIsFine 
    { 
     using Outer = T; 
     using Inner = typename T::B::B::B::B::B::B; 
    }; 

    using ItWillBeOkay = EverythingIsFine<B>; // Probably not ok 
    using InnerProblem = ItWillBeOkay::Inner; // Still not ok 
    using OuterProblem = decltype(B().ItWillBeOkay::Outer::B::B::B 
            ::B::B::B::~B()); // Not even CLOSE to ok 
}; 

Compone sorprendentemente senza avvisi e senza errori con Clang e GCC.
Le versioni dei miei compilatori sono gcc version 5.3.1 20160121 (Debian 5.3.1-7) e Debian clang version 3.6.2-3 (tags/RELEASE_362/final) (based on LLVM 3.6.2) e il flag utilizzato per compilare è -std=c++11 -Wall -Wextra.

Ho osservato che compila anche l'ammenda on Ideone with the C++14 setting.


Allora ho usato questo semplice test per ottenere l'esatto tipo di InnerProblem e OuterProblem:

template <class T> void Type(); 
int main() 
{ 
    Type<A::InnerProblem>(); 
    Type<A::OuterProblem>(); 
} 

Ed entrambi i compilatori riportano gli stessi tipi durante la compilazione del test:

In function main :
main.cpp:20: undefined reference to void Type<A::B>()
main.cpp:21: undefined reference to void Type<void>()

Quello il tipo di InnerProblem è A::B e il tipo di è void.


È in qualche modo consentito dallo standard o è un bug in entrambi i compilatori?
E visto che mi sembra confuso come il mio compilatore, cosa sta realmente accadendo con questo codice?

EDIT: Come seguito semplificato, perché non capisco perché due compilatori non possono dare lo stesso risultato, il seguente codice viene compilato con Clang, ma non con GCC.

struct A 
{ 
    struct B{}; 

    template <typename T> 
    struct EverythingIsFine 
    { 
     using Inner = typename T::B::B::B; 
    }; 

    using Problem = EverythingIsFine<B>::Inner::B::B::B; // Not ok 
}; 

GCC ora emette il seguente errore:

main.cpp:11:26: error: 'A::B::B' names the constructor, not the type using InnerProblem = EverythingIsFine::Inner::B::B::B; // Not ok

+2

Questo codice viene compilato anche su ICC e MSVS – NathanOliver

+0

Nuova domanda -> nuova domanda per favore. Includi un link se il contesto ti aiuta. –

+0

@BaummitAugen Penso che anche la mia nuova domanda sarebbe un errore, quindi mi asterrò questa volta, ma hai ragione. – tux3

risposta

6

E 'valido.

The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name." (9/2).

Così B::B nomi della classe B, come fa B::B::B, e così via.

EDIT:

Così typename B::B nomi della classe B, come fa typename B::B::B, e così via.

+0

Questo ha senso, ma se sostituisco 'InnerProblem = ItWillBeOkay :: Inner' di' InnerProblem = ItWillBeOkay :: Inner :: B :: B :: B; 'ora GCC non riesce a compilare e Clang compila ancora bene, è questo bene -un comportamento definito? GCC dice "A :: B :: B" chiama il costruttore, non il tipo ". – tux3

+0

@ tux3 - Non lo so. Non ho (e non voglio) seguire tutti i typedef annidati nella tua domanda. –

+0

@ tux3 Non ho nemmeno guardato i tuoi pazzi nomi nidificati, ma a giudicare dal messaggio di errore, che potrebbe essere un bug clang, vedi http://stackoverflow.com/q/32006122/241631 – Praetorian

Problemi correlati