2013-05-15 11 views
17

Ho problemi con il seguente codice:nidificati pause struct constexpr pur essendo identici a quelli globali

template<typename T> 
constexpr int get(T vec) { 
    return vec.get(); 
} 

struct coord { 
    constexpr int get() const { return x; } 
    int x; 
}; 

struct foo { 
    struct coord2 { 
     constexpr int get() const { return x; } 
     int x; 
    }; 
    constexpr static coord f = { 5 }; 
    constexpr static int g = get(f); // works 

    constexpr static coord2 h = { 5 }; 
    constexpr static int i = get(h); // doesn't work 
}; 

constexpr coord foo::f; 
constexpr foo::coord2 foo::h; 

int main(){} 

Essenzialmente, get(f) è considerato un'espressione costante, ma non è get(h). L'unica cosa cambiata è che si utilizza una struttura globale coord, mentre l'altra utilizza una struttura nidificata coord2. I corpi della struttura ' sono identici.

Perché è questo? Errore di


GCC:

errore
test.cpp:20:35: error: field initializer is not constant 

Clang:

test.cpp:20:26: error: constexpr variable 'i' must be initialized by a constant expression 
    constexpr static int i = get(h); // doesn't work 
         ^ ~~~~~~ 
test.cpp:8:10: note: undefined function 'get' cannot be used in a constant expression 
    return vec.get(); 
     ^
test.cpp:20:30: note: in call to 'get({5})' 
    constexpr static int i = get(h); // doesn't work 
          ^
test.cpp:13:21: note: declared here 
     constexpr int get() const { return x; } 

risposta

17

Si tratta di un'espressione costante .... alla fine, come questo dimostra che si può vedere spostando i in main():

I messaggi di errore sono abbastanza chiaro che cosa sta succedendo, e cioè che foo::coord2::get() non è ancora definita, in quanto le definizioni di funzioni membro vengono ritardate fino alla fine della classe racchiude in modo che possano utilizzare i membri dichiarati in seguito.

È un po 'sorprendente che la definizione venga ritardata fino alla fine della classe di chiusura più esterna, ma sarete ancora più sorpresi se non fosse possibile accedere a foo::coord2::get()foo::g.

Lo standard è d'accordo con il compilatore, btw. Parte della sezione 9.2p2 dice

Within the class member-specification, the class is regarded as complete within function bodies, default arguments, exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes).

Purtroppo, è dedurre solo che la coppia di dichiarazione della classe di chiusura diventa il punto di definizione per queste regioni differite. Credo che sia un difetto dello Standard che non lo dice esplicitamente.

Consulta anche:

+0

@dyp: Non è che quello che ho detto? (Si deduce, non è esplicito) –

+0

Ah, OK, ho frainteso quel paragrafo, mi dispiace. – dyp

Problemi correlati