2013-05-15 11 views
17

Mam problemy z następującego kodu:zagnieżdżone struct przerwy constexpr pomimo identycznych do tych globalnych

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(){} 

Zasadniczo get(f) uważany jest za stałą ekspresję, ale get(h) nie jest. Zmieniło się tylko to, że używa się globalnej struktury coord, a druga używa zagnieżdżonej struktury coord2. Elementy struktury " są identyczne.

Dlaczego tak jest? Błąd


GCC:

błąd
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; } 

Odpowiedz

17

Jest stałym wyrażeniem .... w końcu, jak pokazuje to widać przesuwając i w main():

Komunikaty o błędach są dość jasne, co się dzieje, co jest foo::coord2::get() nie została jeszcze zdefiniowana, ponieważ definicje funkcji składowych są opóźnione aż do końca klasy otaczającej tak, że mogą korzystać członkowie ogłoszony później.

To trochę zaskakujące, że definicja jest opóźniona aż do końca najbardziej zewnętrznej klasy zamykającej, ale byłbyś jeszcze bardziej zaskoczony, gdyby foo::coord2::get() nie mógł uzyskać dostępu do .

Standard zgadza się z kompilatorem, btw. Część sekcji 9.2p2 mówi

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).

Niestety, to wywnioskować jedynie, że klamra zamykająca deklaracji klasy staje się punktem-of-definicja tych odroczonych regionów. Uważam, że jest to wada Standardu, że nie mówi tego wprost.

Zobacz także:

+0

@dyp: Czy to nie jest to, co powiedziałem? (Jest to wnioskowane, nie jest jednoznaczne) –

+0

Ach, OK, źle zrozumiałem ten akapit, przepraszam. – dyp