2011-12-29 27 views
9

Questo è l'esempio più semplice che è possibile ottenere per riprodurre il problema.Riferimento indefinito a una variabile locale statica

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

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

ho provato con MinGW 4.6 e 4.7, anche g ++ 4.6 in Ubuntu e tutti loro mi danno l'errore di collegamento "undefined reference to` z '". Quindi ora mi chiedo se questo sia persino legale. VC10 non ha alcun problema con esso.

Funziona se X è una classe normale anziché un modello. Inoltre, non penso che sia collegato a lambda perché ottengo l'errore anche se sostituisco il lambda con una classe locale.

+0

aggiungi tag C++ 11, forse ti darà una risposta migliore – marcinj

risposta

10

g ++ accettate, ma VC++ non:

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

Qui z viene catturato così g ++ non denunciare una indefinito riferimento. Tuttavia:

5.1.2/10:

Gli identificatori in una cattura-list vengono ricercati utilizzando le regole usuali per la ricerca dei nomi non qualificati (3.4.1); ciascuna di queste ricerche deve trovare una variabile con durata di archiviazione automatica dichiarata nell'estensione di raggiungimento dello dell'espressione lambda locale.

z è non memorizzazione automatica. z non può quindi essere catturato. il comportamento di g ++ è quindi errato e VC++ è corretto.

Nel codice, che VC++ accetta e g ++ non lo fa:

[]{ z = 1; }(); 

z si accede dalla memoria come statica VC++, che è consentito in un corpo lambda. apparentemente g ++ non risolve il nome z alla variabile statica dichiarata sopra e quindi genera riferimento non definito, mentre non dovrebbe.

tl; dr E 'probabilmente un bug in g ++

Edit: It is indeed a bug ed è fissato in 4.7.

+0

Bello: potrebbe anche spiegare perché il lavoro di TonyK funziona davvero, anche se non sono sicuro che il "riferimento a z" avrebbe memoria automatica. Guardando su 5.2.1/9, si nota anche che il "raggio d'azione" della nota si riferisce agli arresti nella funzione di chiusura più interna, escludendo quindi anche le "globali" (che comunque non hanno una durata di memorizzazione automatica).Sembra quindi completamente inteso che l'elenco di acquisizione possa acquisire solo variabili locali per copia. –

-1

Non capisco perché funzioni per classi normali e non per modelli. Ma è possibile ottenere il tuo esempio a funzionare se si cattura la variabile locale z per riferimento:

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

Wikipedia ha più informazioni here.

+0

Qualcuno di nome @cicada ha postato la stessa risposta ma poi l'ha cancellata (ora sei qui con la stessa risposta), non so perché l'ha cancellata 0_o –

+0

@ Mr.Anubis perché sto ancora cercando di capire perché g ++ si comporta diversamente da VC++ –

+0

@Cicada Entrambi i compilatori sono liberi di comportarsi in modo diverso quando uno ha un bug e l'altro no. –

Problemi correlati