Consider the following code:
template <class>
struct Foo_s {
using type = void();
};
template <class>
using Foo_u = void();
template <class T>
struct Bar {
Foo_u<void> foo1; // OK
typename Foo_s<void>::type foo2; // OK
Foo_u<T> foo3; // OK
typename Foo_s<T>::type foo4; // Boom.
};
template struct Bar<void>;
The declaration of foo4
fails on GCC 7.2, Clang 5.0.0 and MSVC 19.10.25017.
GCC:
<source>: In instantiation of 'struct Bar<void>':
18 : <source>:18:17: required from here
15 : <source>:15:29: error: field 'Bar<void>::foo4' invalidly declared function type
typename Foo_s<T>::type foo4;
^~~~
Clang:
15 : <source>:15:29: error: data member instantiated with function type 'typename Foo_s<void>::type' (aka 'void ()')
typename Foo_s<T>::type foo4;
^
18 : <source>:18:17: note: in instantiation of template class 'Bar<void>' requested here
template struct Bar<void>;
^
MSVC:
15 : <source>(15): error C2207: 'Bar<T>::foo4': a member of a class template cannot acquire a function type
18 : <source>(18): note: see reference to class template instantiation 'Bar<void>' being compiled
All of them seem to think that I am trying to declare a data member with a function type. As you can see, this only happens when the type is nested (not a using
template), and is dependent on the parameter of the class. This looks like a bug, but the fact that for once all of these three compilers agree has me doubting.
Is this standard behaviour? If so, is there a rationale behind disallowing this, and is there a way to declare a member function whose type is computed with a metaprogram?