2015-06-14 12 views
24

[C++14: 7.1.5/1]: L'identificatore constexpr deve essere applicato solo alla definizione di un modello variabile o variabile, alla dichiarazione di un modello funzione o funzione o alla dichiarazione di un membro dati statici di tipo letterale (3.9). Se una dichiarazione di una funzione, modello di funzione o modello variabile ha un identificatore constexpr, tutte le sue dichiarazioni devono contenere l'identificatore constexpr. [..]Perché GCC pensa che la definizione di membro di dati statici di constexpr debba essere contrassegnata come constexpr?

Si noti che la seconda frase non menziona "un membro di dati static" il modo in cui la prima frase fa, quindi non c'è alcun obbligo in questo passaggio che tutte le dichiarazioni (e qui sto considerando specificamente una dichiarazione) di un membro di dati ha l'identificatore constexpr.

Non riesco a trovare una regola altrove per autorizzare questo.

Perché, quindi, GCC rifiuta il seguente programma?

#include <chrono> 

using namespace std::chrono_literals; 

#define DUR 1000ms 

struct T 
{ 
    static constexpr auto dur_1 = DUR; 
}; 

decltype(T::dur_1) T::dur_1; 

// main.cpp:12:23: error: 'constexpr' needed for in-class initialization of static data member 'const std::chrono::duration<long int, std::ratio<1l, 1000l> T::dur_1' of non-integral type [-fpermissive] 
// decltype(T::dur_1) T::dur_1; 
//      ^
+1

Anche la parte relativa a "modelli variabili" è scomparsa nelle bozze recenti. - Modifica: ah, questo è http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1712 – dyp

+0

La taglia sembra andare invano! – anshabhi

+1

@anshabhi: Tristemente :( –

risposta

2

Questo sembra underspecified a me, non vedo un requisito esplicito, ma possiamo capire perché si tratta di un problema da defect report 699: Must constexpr member functions be defined in the class member-specification? che anche se si tratta di funzioni membro constexpr dice quanto segue (sottolineatura mia ):

Se il divieto è stato rilasciato per consentire la dichiarazione separata e la funzione delle funzioni membro constex, è necessario rispondere ad alcune domande a , ad esempio se lo specificatore di constexpr deve apparire su sia dichiarazione che definizione (lo specificatore in linea non è necessario). Se è possibile omettere nell'uno o nell'altro, , esiste un problema di usabilità relativo al fatto che constexpr implica const; il qualificatore const dovrebbe essere specificato esplicitamente nella dichiarazione in cui è stato omesso constexpr.

Anche se in questo caso l'aggiunta di const non risolve il problema, anche se in casi più semplici che sembra risolvere il problema. Possiamo vedere in un caso più semplice sia clang e gcc richiedono sia const o constexpr:

struct T 
{ 
    static constexpr int blah = 1 ; 
}; 

const int T::blah ; 

Aggiornamento

Questo bug report gcc: Bogus "error: redeclaration ... differs in ‘constexpr’" ha la seguente citazione da Richard Smith:

Non esiste alcuna regola che richieda successive dichiarazioni di variabili a concordare in 'constexpr'ness (questa regola si applica solo alle funzioni).

Quindi questo sembra un bug di gcc, anche se sembra ancora che possa usare una certa chiarezza nello standard.

0

Un membro di dati statici di constexpr deve essere inizializzato in classe secondo 7.1.5 (9). Questa è la definizione del membro. A causa dell'ODR non è consentita alcuna altra definizione, quindi T :: dur_1 potrebbe essere solo una dichiarazione. Ma non esiste una regola che consenta la dichiarazione di membri di dati statici const al di fuori del corpo della classe, quindi questa dichiarazione non è consentita.

GCC supporta questo come estensione solo se constexpr viene utilizzato in modo coerente.

O mi sbaglio e si tratta di un bug;)

FWIW: clang accetta questo codice senza un avvertimento.

+1

Non penso che questo è giusto, mi dispiace, la dichiarazione nel corpo della classe non è ancora definita (nonostante l'inizializzatore) e la dichiarazione nello scope dello spazio dei nomi è ancora una definizione –

+1

'[C++ 14: 9.4.2/3]:' _ "** Un membro di dati statici di tipo letterale può essere dichiarato nella definizione di classe con lo specificatore di constexpr **; in tal caso ** la sua dichiarazione deve specificare un inizializzatore di contromossa o uguale ** in cui ogni clausola di inizializzazione che è un'espressione-assegnazione è un'espressione costante. [Nota: in entrambi i casi, il membro può apparire in espressioni costanti. -end note] ** Il membro deve ancora essere definito in un ambito di namespace ** se è odr- usato (3.2) nel programma e ** il nome la definizione dell'ambito dello spazio non deve contenere un inizializzatore **. "_ –

-1

La mia risposta precedente pensava che il problema con il codice era che gli oggetti std :: chrono_literals non erano validi come constexp s, ma come sottolineato da Lightspeed, questo non è il caso.

ho fatto un po 'più di ricerca e determinato che la linea problema con il codice è la tua struct t: in particolare questa linea:

static constexp auto ... 

C'è un'altra risposta su SO su questo here

per puntare in modo esplicito fuori perché questo è il tuo problema (come il commento indica questo non è immediatamente ovvio):

Qualsiasi espressione etichettata constexp deve essere determinata in fase di compilazione. Questo lo sai già. Quando si tenta di creare un'istanza con l'espressione decltype(T::dur_1) T:dur_1, ai propri occhi si forniscono le credenziali appropriate al costruttore crono letterale (che è constexp). Il problema è che il tipo non è definito in modo esplicito in quanto sembra che si tratti della definizione del pre-processore della sostituzione di DUR di 1000 ms.

provare quanto segue:

template <class T> 
struct foo { 
    static constexpr auto dur_1 = DUR; 
    typedef decltype(DUR) milliseconds; 
} 

template <class T> 
constexp milliseconds foo<T>::milliseconds foo<T>::DUR; 

Rimuovendo l'incapacità del compilatore GCC per determinare il tipo di auto al momento della compilazione attraverso la definizione esplicita, si dovrebbe risolvere il problema.

Ecco perché è stato fornito il collegamento originale. GCC non è in grado di determinare correttamente la digitazione automatica in fase di compilazione.

+2

Tranne che il costruttore' std :: chrono :: milliseconds' è contrassegnato come 'constexpr', tutti i tipi interi sono tipi letterali e la definizione del preprocessore suggerita non ha assolutamente senso! Nota su quale riga viene emessa la diagnostica: sulla definizione, non sulla dichiarazione di inizializzazione. –

+0

Grazie per aver provato, però. Questo è, almeno, ben scritto! –

+0

Ho preso il prep prep def come totalmente cattivo.Non sono in una macchina per lo sviluppo in questo momento e la mia idea "off-the-wall" è stata spostata dal mio cervello cosciente dopo che l'ho postata. L'ho già modificato per fornire risorse su un esempio non testato (leggi: bs). Ho ottenuto le mie informazioni dal riferimento C++, e non il riferimento STD (che sto guardando ora). Analizzerò a fondo questa documentazione e correggerò/eliminerò la mia risposta. –

Problemi correlati