2015-03-04 34 views
7

Secondo: constexpr static data member giving undefined reference error membri della classe constexpr statici devono soddisfare due requisiti:inizializzazione uniforme del membro constexpr static

template <typename Tp> 
struct wrapper { 
    static constexpr Tp value{}; // 1 
}; 

template<typename Tp> 
constexpr Tp wrapper<Tp>::value; // 2 

struct foo { 
}; 

int main() { 
    auto const& x = wrapper<foo>::value; 
    (void)x;  
} 
  1. inizializzato all'interno della definizione della classe (perché è constexpr)
  2. definita all'esterno della definizione di classe (perché è statica)

Se cambio 1. a initiali uniformi zazione

template <typename Tp> 
struct wrapper { 
    static constexpr auto value = Tp{}; // uniform initialization 
}; 

template<typename Tp> 
constexpr Tp wrapper<Tp>::value; 

compilatore si lamenta dichiarazioni circa contrastanti:

$ g++ prog.cc -Wall -Wextra -std=c++1z -pedantic 
prog.cc:7:31: error: conflicting declaration 'constexpr const Tp wrapper<Tp>::value' constexpr Tp wrapper<Tp>::value; 
prog.cc:3:29: note: previous declaration as 'constexpr const auto wrapper<Tp>::value' static constexpr auto value = Tp{}; 

e anche circa inizializzatore mancante:

prog.cc:7:31: error: declaration of 'constexpr const auto wrapper<Tp>::value' has no initializer 

Rimozione conflitto 2. estremità di definizione, come previsto, con errore di linker:

In function `main': prog.cc:(.text+0x8): undefined reference to `wrapper<foo>::value' 

Esempio di codice online.

È possibile/legale utilizzare l'inizializzazione uniforme per i membri della classe constexpr statici?

+0

Questo ha qualcosa a che fare con il parametro di template: Funziona come previsto se il tipo del membro dati statico non dipende dal parametro di template, come valore constexpr auto 'statica = int {}; ' – dyp

+0

questa classe wrapper è in realtà una sostituzione del modello di variabile C++ 14 in gcc <5.0, quindi il parametro template è obbligatorio –

+0

Hai bisogno di usare' auto'? –

risposta

0

questo può essere il mio equivoco, ma avrei considerato

struct wrapper { 
    static constexpr Tp value = Tp{}; 
}; 

ad essere un esempio di inizializzazione uniforme. In effetti, il primo esempio di codice è anche un'inizializzazione uniforme. Lo standard stesso richiede semplicemente che questi membri di constexpr statici vengano inizializzati con un'espressione di tipo "coppia o incarico". Questo, come hai già visto, funziona bene.

Il problema sembra essere con la deduzione di tipo da auto in un contesto di modello, e ho il sospetto che sia un bug di implementazione, anche se lo standard è grande, e potrei facilmente aver perso qualcosa.

Se la dimensione della mano destra dell'inizializzazione di constexpr era un'espressione con un tipo difficile da predeterminare, una soluzione alternativa sarebbe utilizzare decltype, ad es.

template <typename Tp> 
struct wrapper { 
    static constexpr decltype(complex-init-expr) value = complex-init-expr; 
}; 

template <typename Tp> 
static constexpr decltype(complex-init-expr) wrapper<Tp>::value; 

o

template <typename Tp> 
struct wrapper { 
    typedef decltype(complex-init-expr) value_type; 
    static constexpr value_type value = complex-init-expr; 
}; 

template <typename Tp> 
static constexpr typename wrapper<Tp>::value_type wrapper<Tp>::value; 
Problemi correlati