Undefined link, struct template and constexpr static member

I am having a problem with the constexpr static element of a template structure. The code compiles, but I get a binding error. Here is what I am trying to do:

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

I had communication errors with this, so I tried this:

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

But instead, I got this strange error:

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

Another type? Obviously, the non-template version works just fine:

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

How can I make the template version work? Thank you very much

+5
source share
2 answers

How can I make the template version work?

FWIW, your method works fine on my desktop that uses g ++ 4.8.4.

You can use:

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

The following also works on my 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
source

It looks like you are facing an interesting corner case with decltype, this is described in the clang error report Static definitions of constexpr used inside a template that has the following example with a similar error like yours:

This compiles fine, but when I make class A, create 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 as follows:

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

and Richard Smith's answer was as follows:

This error is correct. "constexpr" and "auto" are red herrings. Reduced Test:

 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 the expression e includes a template parameter, decltype (e) indicates a unique dependent type. A :: F type does not match the type in the template.

The full quote for this from the C ++ 14 project is as follows:

If the expression e includes a template parameter, decltype (e) indicates a unique dependent type. Two such pointers are of the same type only if their expressions are equivalent (14.5.6.1). [Note: however, it can be an alias, for example, using typedef-name. -end note]

The only obvious way I see to get this working:

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

No action was suggested in the error report.

+3
source

Source: https://habr.com/ru/post/1234498/


All Articles