2011-12-29 10 views
9

To najprostszy przykład, jaki mogłem wymyślić, który odwzorowuje problem.Niezdefiniowane odniesienie do statycznej zmiennej lokalnej

template<class T> 
struct X 
{ 
    static void foo() 
    { 
     static int z = 0; 
     []{ z = 1; }(); 
    } 
}; 

int main() 
{ 
    X<int>::foo(); 
    return 0; 
} 

Próbowałem go z MinGW 4.6 i 4.7, a także g ++ 4.6 w Ubuntu i wszystkie z nich daje mi błąd Link "niezdefiniowana odniesienia do` z '". Więc teraz zastanawiam się, czy to nawet legalne. VC10 nie ma z tym problemu.

Działa, jeśli X jest normalną klasą zamiast szablonu. Ponadto, nie sądzę, że jest to związane z lambdami, ponieważ dostaję błąd, nawet jeśli zamieniam lambdę na lokalną klasę.

+0

Dodaj tag C++ 11, może to da ci lepszą odpowiedź – marcinj

Odpowiedz

10

g ++ przyjmuje następujące, lecz nie VC++:

[&z]{ z = 1; }(); 

tutaj z jest zrobione tak g ++ nie skarży się na nieokreślonej odniesieniu. Jednakże:

5.1.2/10:

The identyfikatorów w capture-liście są spojrzał stosując zwykłe zasady niewykwalifikowanego nazwa odnośnika (3.4.1); każde takie wyszukiwanie powinno znaleźć zmienną o automatycznym czasie przechowywania zadeklarowanym w zasięgu osiągnięcia lokalnego wyrażenia lambda.

z jest nie automatyczne przechowywanie. W związku z tym z nie można przechwycić. zachowanie g ++ jest zatem niepoprawne, a VC++ jest poprawne.

W kodzie, że VC++ akceptuje i g ++ nie:

[]{ z = 1; }(); 

z jest dostępna przez VC++ jako statycznego przechowywania, które jest dozwolone w organizmie lambda. g ++ najwyraźniej nie rozpoznaje nazwy zmiennej zadeklarowanej powyżej i dlatego wyrzuca niezdefiniowane odniesienie, podczas gdy nie powinno.

tl; dr To chyba błąd w g ++

Edit: It is indeed a bug i jest ustalony w punkcie 4.7.

+0

Miło: może to nawet wyjaśnić, dlaczego praca TonyK faktycznie działa, chociaż nie jestem pewien, czy "odniesienie do z" miałoby automatyczne przechowywanie. Patrząc w górę 5.2.1/9, zauważamy również, że "zasięg działania" oznacza nutę w najgłębszej funkcji zamykającej, a więc również wykluczającą "globale" (które i tak nie mają czasu automatycznego przechowywania).Wygląda więc na to, że lista przechwytywania może przechwytywać tylko zmienne lokalne przez kopiowanie. –

-1

Nie rozumiem, dlaczego działa dla normalnych klas, a nie dla szablonów. Ale można uzyskać przykład do pracy, jeśli uchwycić zmienną lokalną z przez odniesienie:

static void foo() 
{ 
    static int z = 0; 
    [&z]{ z = 1; }(); // Note: [&z] 
} 

Wikipedia ma więcej informacji here.

+0

Ktoś o imieniu @cicada opublikował tę samą odpowiedź, ale potem ją usunął (teraz jesteś tutaj z tą samą odpowiedzią), nie wiem, dlaczego ją usunęła 0_o –

+0

@ Mr.Anubis, ponieważ wciąż próbuję zrozumieć dlaczego g ++ zachowuje się inaczej niż VC++ –

+0

@Cicada Oba kompilatory mogą zachowywać się inaczej, jeśli ktoś ma błąd, a inny nie. –

Powiązane problemy