2012-06-06 22 views
6

El siguiente código demuestra un comportamiento de gcc 4.6.2 que no puedo explicar. La primera función declara una matriz estática de tipo vec_t, donde vec_t es un alias typedef'd para char sin signo. La segunda función es idéntica, excepto que el tipo de vect_t es un parámetro de plantilla. La segunda función no puede compilarse con el error de diagnóstico: el tamaño de almacenamiento de 'bitVec' no es constante ".¿Error del compilador? g ++ permite matrices estáticas de tamaño variable, a menos que la función esté templada

#include <limits> 

void bitvec_func() 
{ 
    const std::size_t  nbits = 1e7; 
    typedef unsigned char vec_t; 
    const std::size_t  WLEN = std::numeric_limits<vec_t>::digits; 
    const std::size_t  VSIZ = nbits/WLEN+1; 
    static vec_t   bitVec[nbits/VSIZ]; // Compiles fine 
} 

template <typename T> 
void bitvec_func() 
{ 
    const std::size_t  nbits = 1e7; 
    typedef T    vec_t; 
    const std::size_t  WLEN = std::numeric_limits<vec_t>::digits; 
    const std::size_t  VSIZ = nbits/WLEN+1; 
    static vec_t   bitVec[nbits/VSIZ]; // "error: storage size of ‘bitVec’ isn’t constant" 
} 

void flarf() 
{ 
    bitvec_func(); 
    bitvec_func<unsigned char>(); 
} 

Me parece que una instancia de la plantilla con el argumento < unsigned char> debería hacer que el compilador generar el mismo código que la primera función. ¿Alguien puede ofrecer alguna idea de por qué este no parece ser el caso?

[Adición: la segunda función se compilar con "-std = C++ 0x" o "-std = gnu ++ 0x", pero todavía me gustaría entender cómo/si está mal bajo la anteriores definiciones de la lengua]

ETA:.
la segunda función compilará si el inicializador para nbits se cambia:

const std::size_t  nbits = 1e7;    // Error 
const std::size_t  nbits = (std::size_t)1e7; // Okay 
const std::size_t  nbits = 10000000.0;  // Error 
const std::size_t  nbits = 10000000;   // Okay 

En otras palabras, parece que si nbits se inicia con una expresión de una integral tipo, entonces nbits se trata como constante en la definición de bitVec. Si nbits se inicializa con una expresión de coma flotante, el compilador ya no lo ve como constante en la expresión de la dimensión bitVec, y la compilación falla.

Soy mucho menos cómodo llamando "error de compilación" en C++ que en C, pero no puedo pensar en ninguna otra razón por la que los 4 casos anteriores no sean semánticamente idénticos. ¿Alguien más se preocupa por opinar?

+0

¿Podría publicar el código exacto que le está dando un error de compilación? Parece que no puedo reproducirlo. –

+0

Ese es el código exacto de arriba. El compilador es gcc 4.6.2 y las opciones son "-O0 -g3 -c". –

+1

En un gcc 4.3.4 anterior, este código [compilado bien] (http://ideone.com/65Cl7). –

Respuesta

6

Después de compilar el código con -ansi en gcc 4.7.0, yo era capaz de reproducir esta advertencia:

warning: ISO C++ forbids variable length array 'bitVec' [-Wvla] 

Esta advertencia apareció por tantobitVec, no sólo el de la función de plantilla. Luego me di cuenta de que la línea nbits = 1e7; está asignando un double a un unsigned int. Creo que debido a esto, por alguna razón hace que nbits no sea una expresión constante. La razón por la cual su código se está compilando para la versión no templada es debido a la extensión de matriz de longitud variable para gcc. Además, su versión de gcc por alguna razón no permite matrices de longitud variable en plantillas de funciones. Para arreglar su código, cambie 1e7; a 10000000.

EDITAR

me preguntó another question correspondiente a la norma. La respuesta está en C++ 03 el código no es válido, pero en C++ 11 está bien.

+0

no está perdiendo su atributo' const', sino el atributo (implied) 'constexpr'. –

+0

@MooingDuck: Eso es cierto (corregido). Sin embargo, todavía me pregunto por qué ese es el caso. –

+0

'1e7' y' 0x1e7' son números muy diferentes. '10000000' sería una mejor sustitución. – aschepler

0

Seguramente la respuesta es que en la etapa de compilación donde se genera ese error, el tamaño de almacenamiento del índice de matriz no es constante, es decir, es anterior a la expansión de la plantilla. Las matrices dinámicas no son parte de C++ 98/03, son una extensión de gcc (a C, originalmente). Entonces, el error es correcto, incluso si la implementación se ve extraña. Es de suponer que GCC alcanza una ruta de cumplimiento de normas para matrices con plantillas, admitiéndolas donde sea necesario y arrojando un error de lo contrario, pero las matrices de tipos estáticos tocan la ruta "C" y así recogen la extensión gcc automáticamente.

+1

El código en realidad no tiene matrices variables, por lo que el error es _wrong_. El tamaño de la matriz se conoce en tiempo de compilación y debe ser tratado como tal por un compilador conforme. –

+0

No es simplemente un problema de variabilidad de tiempo de ejecución. Creo (pero soy demasiado perezoso comprobar) que C++ 03 no permite los parámetros de la plantilla específicamente en los inicializadores de tamaño de matriz (precisamente debido al problema del huevo y la gallina al expandirlos en el momento adecuado). Sin duda, alguien con un mejor conocimiento de la especificación vendrá a corregirme. –

+0

Interesante. Esto (desorden) funciona: 'plantilla void a() { typedef T \t \t vec_t; estático vec_t \t bitVec [sizeof (vec_t) * 8]; } ' –

Cuestiones relacionadas