2015-10-26 4 views
5

У меня возникла проблема со статическим элементом constexpr структуры шаблона. Код компилируется, но я получаю ошибку связывания. Вот что я пытаюсь сделать:Неопределенная ссылка, шаблон struct и constexpr static member

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; 
} 

я получил связь ошибки с, так что я попытался это:

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; 
} 

Но вместо этого я получил эту странную ошибку:

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

Другой тип? Очевидно, что версия не-шаблон работает просто отлично:

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; 
} 

Как я могу узнать версию шаблона для работы? Большое спасибо

+0

Я добавил C++ 14, так как 'make_tuple' не является constexpr до тех пор. –

ответ

1

How can I get the template version to work?

FWIW, ваш метод отлично работает на моем рабочем столе, который использует г ++ 4.8.4.

Вы можете использовать:

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

Следующая также работает на моем рабочем столе:

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

Единственное решение, которое, похоже, работает: 'decltype (make_tuple (2," test ", 3.4))' Я использую GCC 5.2.0 и Clang 3.7.0 –

+0

Странно, что g ++ 5.2.0 не работает во время g ++ 4.8.4 работает. –

3

Похоже, что вы работаете в интересный угловой корпус с decltype, это рассматривается в лязгом отчет об ошибке Static constexpr definitions used inside template, который имеет следующий пример с аналогичной ошибкой:

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(); 
         ^

и ответ Ричарда Смита следующим образом:

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.

полная котировка, что из проекта C++ 14 выглядит следующим образом:

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 ]

Единственный очевидный способ, которым я могу видеть, чтобы получить это работа:

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

В отчете об ошибке не было предложено никаких работ.

 Смежные вопросы

  • Нет связанных вопросов^_^