2011-12-29 23 views
9

Este es el ejemplo más simple que pude encontrar que reproduce el problema.Referencia no definida a una variable local estática

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

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

Lo he intentado con MinGW 4.6 y 4.7, también g ++ 4.6 en Ubuntu y todos ellos me dan el error de enlace "referencia indefinida a` z '". Entonces eso me hace preguntarme si esto es legal. VC10 no tiene problema con eso.

Funciona si X es una clase normal en lugar de una plantilla. Además, no creo que esté relacionado con lambdas porque me da el error incluso si reemplazo el lambda con una clase local.

+0

agregue la etiqueta C++ 11, tal vez le dará una mejor respuesta – marcinj

Respuesta

10

g ++ acepta las siguientes, pero VC++ no:

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

Aquí z se está capturando así g ++ no se quejan de un referencia indefinida. Sin embargo:

5.1.2/10:

Los identificadores en una captura-list se buscan utilizando las reglas habituales de búsqueda de nombre no calificado (3.4.1); cada búsqueda de este tipo encontrará una variable con la duración de almacenamiento automática declarada en el alcance de la expresión local lambda.

z es no almacenamiento automático. z por lo tanto, no se puede capturar. El comportamiento de g ++ es, por lo tanto, incorrecto y VC++ es correcto.

En su código, que VC++ acepta y g ++ no:

[]{ z = 1; }(); 

z se accede por el almacenamiento como estática VC++, que se deja en un cuerpo lambda. g ++ aparentemente no resuelve el nombre z en la variable estática declarada anteriormente y por lo tanto arroja referencia indefinida, mientras que no debería.

tl; dr Es probablemente un error en g ++

Editar: It is indeed a bug y se fija en 4,7.

+0

Agradable: incluso podría explicar por qué funciona el trabajo de TonyK, aunque no estoy seguro de si la "referencia a z" tendría almacenamiento automático. Al buscar 5.2.1/9, también se observa que el alcance de alcance de su nota se refiere a las paradas en la función de encerramiento más interna, por lo que también excluye los "globales" (que de todos modos no tienen duración de almacenamiento automático).Parece que la lista de captura solo captura las variables locales por copia. –

-1

No entiendo por qué funciona para las clases normales y no para las plantillas. Pero usted puede conseguir su ejemplo funcione si captura la variable local z por referencia:

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

Wikipedia tiene más información here.

+0

Alguien llamada @cicada publicó la misma respuesta pero luego la eliminó (ahora estás aquí con la misma respuesta), no sé por qué la eliminó 0_o –

+0

@ Mr.Anubis porque todavía estoy tratando de descubrir por qué g ++ se comporta de forma diferente que VC++ –

+0

@Cicada Ambos compiladores son libres de comportarse de manera diferente cuando uno posiblemente tiene un error y otro no. –

Cuestiones relacionadas