2015-10-26 17 views
5

Ho riscontrato qualche problema con un membro constexpr statico di una struttura template. Il codice viene compilato ma ricevo un errore di collegamento. Ecco quello che sto cercando di fare:Riferimento non definito, template struct e membro statico di constexpr

template<int n> 
struct Test { 
    static constexpr auto invoke = make_tuple(2, "test", 3.4); 
}; 

template<typename T> 
void test(T&& t) { 
    cout << t << endl; 
} 

int main() { 
    test(get<0>(Test<2>::invoke)); 
    return 0; 
} 

mi sono collegando gli errori con questo, quindi ho provato questo:

template<int n> 
struct Test { 
    static constexpr auto invoke = make_tuple(2, "test", 3.4); 
}; 

// declare it outside the class 
template<int n> 
constexpr decltype(Test<n>::invoke) Test<n>::invoke; 

template<typename T> 
void test(T&& t) { 
    cout << t << endl; 
} 

int main() { 
    test(get<0>(Test<2>::invoke)); 
    return 0; 
} 

Ma invece ho ottenuto questo strano errore:

error: redefinition of 'invoke' with a different type: 'const decltype(Test<n>::invoke)' vs 'const std::tuple<int, const char *, double>' 

Un tipo diverso ?? Ovviamente, la versione non-modello funziona bene:

struct Test { 
    static constexpr auto invoke = make_tuple(2, "test", 3.4); 
}; 

constexpr decltype(Test::invoke) Test::invoke; 

template<typename T> 
void test(T&& t) { 
    cout << t << endl; 
} 

int main() { 
    test(get<0>(Test::invoke)); 
    return 0; 
} 

Come posso ottenere la versione modello di lavorare? Grazie mille

+0

Ho aggiunto C++ 14 poiché 'make_tuple' non è constexpr fino ad allora. –

risposta

1

How can I get the template version to work?

FWIW, il tuo metodo funziona bene sul mio desktop, che utilizza g ++ 4.8.4.

È possibile utilizzare:

template<int n> 
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke; 

Di seguito funziona anche sul mio desktop:

template<int n> 
struct Test { 
    static constexpr auto invoke = make_tuple(2, "test", 3.4); 
    typedef decltype(invoke) invoke_t; 
}; 

template<int n> 
constexpr typename Test<n>::invoke_t Test<n>::invoke; 
+1

L'unica soluzione che sembra funzionare è 'decltype (make_tuple (2," test ", 3.4))' Sto usando GCC 5.2.0 e Clang 3.7.0 –

+0

Questo è strano che g ++ 5.2.0 non funzioni mentre g ++ 4.8.4 funziona. –

3

Sembra che si esegue in un caso d'angolo interessante con decltype, questo è trattato nel clangore bug report Static constexpr definitions used inside template che ha il seguente esempio con un errore simile al tuo:

This compiles fine, but when I make the class A, a template like this:

struct L 
{ 
    void operator()() const 
    {} 
}; 

template<class X> 
struct A 
{ 
    static constexpr auto F = L(); 
}; 

template<class X> 
constexpr decltype(A<X>::F) A<X>::F; 

int main() 
{ 
    A<void>::F(); 
    return 0; 
} 

Clang crashes, if I change the definition line for F to this:

template<class X> 
constexpr typename std::remove_const<decltype(A<X>::F)>::type A<X>::F; 

Then clang produces this error:

error: redefinition of 'F' with a different type 
constexpr typename std::remove_const<decltype(A<X>::F)>::type A<X>::F; 
                    ^
note: previous definition is here 
    static constexpr auto F = L(); 
         ^

e la risposta di Richard Smith è stato il seguente:

This error is correct. 'constexpr' and 'auto' are red herrings here. Reduced testcase:

template<class X> struct A { static int F; }; 
template<class X> decltype(A<X>::F) A<X>::F; 

Per C++11 [temp.type]p2, "If an expression e involves a template parameter, decltype(e) denotes a unique dependent type." Therefore the type of A::F does not match the type in the template.

la citazione completa per che dal progetto di C++ 14 è il seguente:

If an expression e involves a template parameter, decltype(e) denotes a unique dependent type. Two such decltype-specifiers refer to the same type only if their expressions are equivalent (14.5.6.1). [ Note: however, it may be aliased, e.g., by a typedef-name. —end note ]

L'unico modo ovvio posso vedere per ottenere questo il lavoro è:

template<int n> 
constexpr decltype(make_tuple(2, "test", 3.4)) Test<n>::invoke; 

Nessun errore è stato offerto nella segnalazione di errore.