2015-01-22 25 views
10

Nel seguente codice C++ 11, l'ultima chiamata a arraySize causa un errore di compilazione. Apparentemente questo è dovuto al fatto che y è un array di dimensioni runtime, e il parametro N di template arrayize non può essere dedotto per y. Non capisco perché x è un array di dimensioni temporali compilate, ma y ha dimensioni di runtime. La funzione template arraysize è presa direttamente da Scott Meyers' "Effective C++ moderno" Articolo 1.C++: Perché questo constexpr non è una costante di tempo di compilazione

#include <cstddef> 

template<typename T, std::size_t N> 
constexpr std::size_t arraySize(T(&)[N]) noexcept { return N; } 

struct S 
{ 
    char c[10]; 
}; 

int main() 
{ 
    S s; 
    S* ps = &s; 

    char x[arraySize(s.c)]; 
    char y[arraySize(ps->c)]; // why is y a runtime sized array? 

    arraySize(x); 
    arraySize(y); // error !? 

    return 0; 
} 
+0

Qual è l'errore? –

+0

beh io sono stumped ... sia 'sc' che' ps-> c' hanno lo stesso tipo, come spited di 'typeid (sc) .name()' o 'typeid (ps-> c) .name() ', es'A10_c' per g ++ – vsoftco

+0

Per scurirlo un po 'di più: se si imposta il parametro' arraySize() 'come riferimento a const, la seguente compilazione:' char y [arraySize (decltype (ps-> c) {})]; ' – Quentin

risposta

9

In C++, l'errore non è la chiamata alla arraySize(y), ma la dichiarazione di y stessa.

I limiti di una dichiarazione di matrice devono essere "espressione costante convertita".

Se il compilatore accetta la dichiarazione di y e poi si dice che y è un array di runtime legato, non è un compilatore C++. Non ci sono matrici di limiti di runtime in alcuna versione ratificata di C++, né la bozza corrente.

La differenza significativa tra arraySize(s.c) e arraySize(ps->c) è che ps->c è la stessa (*ps).c e l'operatore * dereferenziazione richiede conversione Ivalue a rvalue su ps, che non è un'espressione costante (né è &s, vedi sotto). Il resto dell'espressione non coinvolge la conversione da lvalue a rvalue, l'array lvalue è direttamente vincolato dal riferimento.

Un'espressione costante è o un nucleo glvalue un'espressione costante il cui valore si riferisce a un'entità che è un risultato permesso di un'espressione costante (come sotto definito), o un prvalue nucleo un'espressione costante il cui valore è un oggetto in cui, per tale oggetto e gli oggetti secondari:

  • ciascun membro dati non-statico del tipo di riferimento si riferisce a un'entità che è il risultato di una costante consentita espressione e

  • i Se l'oggetto o subobject è di tipo puntatore, contiene l'indirizzo di un oggetto con durata di memorizzazione statica, l'indirizzo oltre la fine di tale oggetto (5.7), l'indirizzo di una funzione o un valore di puntatore nullo.

Un'entità è il risultato consentito di un'espressione costante se è un oggetto con durata di conservazione statica che è o non è un oggetto temporaneo o è un oggetto temporaneo cui valore soddisfa es limiti sopra descritti, o è un funzione.

Chiaramente ps contiene l'indirizzo di un oggetto con durata di conservazione automatico, quindi non può essere dichiarato constexpr. Ma tutto dovrebbe iniziare a lavorare se si cambia S s; S* ps = &s;-static S s; constexpr S* ps = &s;

(D'altra parte, si potrebbe pensare che il parametro da arraySize(s.c) non è un'espressione costante sia, dal momento che è un punto di riferimento e non un oggetto di archiviazione statica durata)

+0

"Se il compilatore accetta la dichiarazione di y e successivamente ti dice che y è un array di limiti di runtime, non è un compilatore C++." - Questa parte non è vera, un'implementazione conforme (compilatore) è espressamente autorizzata a "accettare" (cioè compilare e/o eseguire) input non formali tramite le estensioni, vedere ad es. 1.4/8 nella bozza N4296. L'implementazione ** è ** richiesta per emettere una diagnostica in questo caso, e GCC e clang non riescono a emettere un avvertimento per gli array di lunghezza variabile a meno che l'opzione -pedantic non venga aggiunta al richiamo. –

Problemi correlati