2014-10-04 11 views
7

Come mai che le seguenti opere in gcc, ma non lo fa sulla clang, (see it live):Consecutivo statico utilizzato o no?

constexpr int giveMeValue() { return 42; } 

struct TryMe { 
    static constexpr int arr[1] = { 
     giveMeValue() 
    }; 
}; 

int main() { 
    int val = TryMe::arr[0]; 
    return val; 
} 

ottengo un simbolo esterno non risolto con clangore.

È TryMe::arr[0] un oggetto? Se lo è, è odr-used?

+1

Quale versione di clang? –

+0

Quello sul coliru – Dean

+0

funziona bene per me: http://coliru.stacked-crooked.com/a/2b319b9351784244 Hai attivato il flag 'C++ 11'? – texasbruce

risposta

7

TryMe::arr è odr-used ma non si fornisce una definizione (see it live):

constexpr int TryMe::arr[1]; 

Perché è il risultato incoerenti tra gcc e clang? Questo perché le violazioni ODR non richiedono una disagnostic, sia dal C++ 11 e C++ 14 progetto di norma (sottolineatura mia):

Ogni programma deve contenere esattamente una definizione di ogni non-inline funzione o variabile che è odr-usata in quel programma; non è richiesta la diagnosi .

Lo possiamo vedere è ODR-usato dal progetto di 11 standard di C++, sezione 3.2 che dice:

Un'espressione è potenzialmente valutata a meno che non si tratta di un non valutata operando (clausola 5) o una sottoespressione di ciò. Una variabile il cui nome appare come un'espressione potenzialmente valutata è odr-used a meno che non sia un oggetto che soddisfi i requisiti per apparire in un'espressione costante (5.19) e la conversione lvalue-rvalue (4.1) sia immediatamente applicato.

TryMe::arr è un oggetto e lo fa soddisfare i requisiti per essere apparso in un'espressione costante ma la conversione lvalue a rvalue non viene immediatamente applicato al TryMe::arr ma TryMe::arr[0].

La formulazione aggiornata dal progetto di C++ 14 standard che si applica al C++ 11 così da quando è stato applicato tramite un rapporto difetti (DR 712):

A x variabile il cui nome appare come un'espressione potenzialmente valutata ex è odr-used a meno che non si applichi la conversione da lvalue a rvalue (4.1) a xa x restituisce un'espressione costante (5.19) che non richiama alcuna funzione non banale e, se x è un oggetto, ex è un elemento del set di potenziali risultati di un'espressione e, dove sia lo lvalue-to-rvalue conversione (4.1) viene applicato e, oppure e è un'espressione scartato valore

I potenziali risultati dell'espressione TryMe::arr[0] è vuota dai criteri di 3.2 punto 2 e così è odr-usato.

Nota: è necessario fornire una definizione al di fuori della classe di cui al punto 9.4.2[class.static.data] che dice (sottolineatura mia):

un membro di dati statici di letterali il tipo può essere dichiarato nella classe definizione con lo specificatore constexpr; in tal caso, la sua dichiarazione deve specificare un inizializzatore di coppia o uguale in cui ogni clausola di inizializzazione che è un'espressione di assegnazione è un'espressione costante. [Nota: nel entrambi questi casi, il membro può apparire in espressioni costanti. -end nota] L'utente deve ancora essere definito in un ambito namespace se è ODR-utilizzato (3.2) nel programma e la definizione dello spazio dei nomi ambito non devono contenere un inizializzatore

Aggiornamento

TC sottolineato defect report 1926 che aggiunge la seguente proiettile 3.2 [basic.def.odr] paragrafo 2:

  • se E è un'operazione di indicizzazione (5.2.1 [expr.sub]) con un operando matrice, la set contiene quell'operando.

che significa indicizzazione di un array non è più un ODR uso e quindi il codice PO sarebbe ben formata in 1Z C++ e sembra C++ 14 poiché il difetto sembra che sia contro C++ 14.

+0

Altri chiarimenti sulla dichiarazione vs definizione. Quale OP abbia nella sua struttura 'TryMe' può sembrare una definizione, ma in realtà è una dichiarazione a causa delle buffe regole su quando una dichiarazione è anche una definizione.Qui OP ha una variabile 'static' con un inizializzatore di membro in classe, che di solito non è consentito, ma qui è permesso a causa di' constexpr' (e 'int'). Tuttavia, OP non ha effettivamente assegnato memoria per 'TryMe :: arr' perché la variabile è anche' static' che richiede memoria esterna. Quindi, come ogni variabile 'static', l'OP deve ancora fornire una dichiarazione al di fuori della struct. – AndyG

+0

(Continua commento precedente perché sono rimasto senza camera). Tuttavia, non è una buona idea fornire la definizione 'constexpr int TryMe :: arr [1];' nello stesso file che OP definisce la struttura 'TryMe' perché qualsiasi classe che voglia includere la definizione per struct' TryMe' quindi tentare di allocare memoria per 'TryMe :: arr [1]', violando la regola di una definizione. Quindi, di solito accade invece che si inserisca 'constexpr int TryMe :: arr [1]' in un file .cpp di qualche tipo, separato dall'intestazione. – AndyG

+0

@AndyG equo punto, ho assunto alcune conoscenze, avrei dovuto aggiungere più dettagliato. Lasciami aggiungere ulteriori dettagli. –