2012-06-06 6 views
6

Il codice seguente mostra un comportamento di gcc 4.6.2 di cui non posso tenere conto. La prima funzione dichiara una matrice statica di tipo vec_t, dove vec_t è un alias typedef per char non firmato. La seconda funzione è identica, tranne per il fatto che il tipo di vect_t è un parametro del modello. La seconda funzione non riesce a compilare con l'errore "diagnostico": la dimensione di archiviazione di "bitVec" non è costante ".Errore del compilatore? g ++ consente matrici statiche di dimensioni variabili, a meno che la funzione non sia basata su modelli.

#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>(); 
} 

Mi sembra che istanziare il modello con l'argomento < unsigned char> dovrebbe causare il compilatore di generare lo stesso codice come la prima funzione. Qualcuno può offrire qualche idea sul perché questo non sembra essere il caso?

[Addendum: la seconda funzione sarà compilare con "-std = C++ 0x" o "-std = gnu ++ 0x", ma mi piace ancora di capire come/se è sbagliato sotto il definizioni lingua precedenti]

ETA:.
la seconda funzione di compilazione se l'inizializzatore per nbits è cambiato:

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 

In altre parole, sembra che se nbits viene inizializzato con un'espressione di un integrale digitare, quindi nbits viene considerato come un costante nella definizione di bitVec. Se nbits viene invece inizializzato con un'espressione a virgola mobile, il compilatore non lo vede più come costante nell'espressione per la dimensione di bitVec e la compilazione non riesce.

Sono molto meno comodo chiamare "bug del compilatore" in C++ di quanto sarebbe in C, ma non riesco a pensare ad alcun'altra ragione per cui i suddetti 4 casi non sarebbero semanticamente identici. Qualcun altro si preoccupa di opina?

+0

Potresti pubblicare il codice esatto che ti dà un errore del compilatore? Non riesco a riprodurlo. –

+0

Questo è il codice esatto sopra. Il compilatore è gcc 4.6.2 e le opzioni sono "-O0 -g3 -c". –

+1

Su un vecchio gcc 4.3.4, questo codice [compilato bene] (http://ideone.com/65Cl7). –

risposta

6

Dopo aver compilato il codice con -ansi su gcc 4.7.0, sono stato in grado di riprodurre questo avvertimento:

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

Questo avviso è apparso per siabitVec, non solo quello nella funzione template. Mi sono poi reso conto che la linea nbits = 1e7; assegna un double a un unsigned int. Penso che per questo motivo, per qualche motivo, non sia nbits un'espressione costante. Il motivo per cui il codice è in fase di compilazione per la versione non basata su modelli è dovuto all'estensione dell'array di lunghezza variabile per gcc. Inoltre, la tua versione di gcc per qualche motivo non consente matrici di lunghezza variabile nei modelli di funzione. Per correggere il cambio di codice 1e7; a 10000000.

EDIT

ho chiesto another question relativa alla regola. La risposta è in C++ 03, il codice non è valido, ma in C++ 11 va bene.

+0

non sta perdendo l'attributo' const', ma l'attributo (implicito) 'constexpr'. –

+0

@MooingDuck: È vero (corretto). Tuttavia, mi chiedo ancora perché sia ​​così. –

+0

'1e7' e' 0x1e7' sono numeri molto diversi. '10000000' sarebbe una sostituzione migliore. – aschepler

0

Sicuramente la risposta è che nella fase di compilazione in cui viene generato quell'errore, la dimensione di archiviazione dell'indice di matrice non è costante, vale a dire che è a monte dell'espansione del modello. Gli array dinamici non fanno parte di C++ 98/03, sono un'estensione gcc (in C, in origine). Quindi l'errore è in realtà corretto, anche se l'implementazione sembra strana. Presumibilmente GCC raggiunge un percorso di conformità agli standard per gli array basati su modelli, supportandoli laddove richiesto e rilasciando un errore in caso contrario, ma le matrici di tipi statici colpiscono il percorso "C" e quindi prelevano automaticamente l'estensione gcc.

+1

Il codice in realtà non ha array variabili, quindi l'errore è _wrong_. La dimensione dell'array è nota al momento della compilazione e dovrebbe essere trattata come tale da un compilatore conforme. –

+0

Non è semplicemente un problema di variabilità di runtime. Credo (ma sono troppo pigro per controllare), che C++ 03 non consente i parametri del template specificatamente negli inizializzatori della dimensione dell'array (precisamente a causa del problema dell'uccellino e dell'uovo con la loro espansione al momento giusto). Senza dubbio qualcuno con una migliore conoscenza delle specifiche verrà a correggermi. –

+0

Interessante. Questo (pasticcio) funziona: 'modello void a() { typedef T \t \t vec_t; static vec_t \t bitVec [sizeof (vec_t) * 8]; } ' –

Problemi correlati