Suppose we have code:
template <int Size>
struct A {
template <typename T, typename Enable = void> struct B;
template <> struct B<bool, std::enable_if_t<Size >= 1>> {};
template <> struct B<short, std::enable_if_t<Size >= 2>> {};
};
template <int Size>
struct D {
template <typename T> struct E;
template <> struct E<bool> {};
template <> struct E<short> {};
};
template <int Size>
struct F {
template <typename T> struct G {};
};
template <int Size, typename T, typename Enable = void> struct C;
template <int Size> struct C<Size, bool, std::enable_if_t<Size >= 1>> {};
template <int Size> struct C<Size, short, std::enable_if_t<Size >= 2>> {};
Structs C and F compile well in all of CLang/GCC/MSVC. Struct D compiles well in CLang/MSVC, but has compile error in GCC. Struct A doesn't compile by all of CLang/GCC/MSVC.
GCC's error for D (similar for A):
<source>:19:15: error: explicit specialization in non-namespace scope 'struct D<Size>'
19 | template <> struct E<bool> {};
CLang's error for A:
type_traits:2514:44: error: no type named 'type' in 'std::enable_if<false>'; 'enable_if' cannot be used to disable this declaration
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
MSVC's error for A:
<source>(11): error C2938: 'std::enable_if_t<false,void>' : Failed to specialize alias template
<source>(11): note: see reference to alias template instantiation 'std::enable_if_t<false,void>' being compiled
<source>(30): note: see reference to class template instantiation 'A<1>' being compiled
<source>(11): error C2913: explicit specialization; 'A<1>::B' is not a specialization of a class template
I have several questions:
Is it at all allowed in std C++ to SPECIALIZE templated sub-class? What are the limitations? Looks like GCC doesn't allow at all and CLang/MSVC allow but with certain limits.
Is it at all allowed to HAVE templated sub-class. If allowed then how do I specialize it? Maybe some out-of-class specialization is allowed for them (then what's the syntax)?
If not allowed to specialize templated sub-class then at least is it allowed to have fully-defined templated sub-class (without specializations)? Looks like struct F above uses fully-defined templated sub-class and compiles well everywhere.
A
doesn't workYou can notice the difference between A
and F
, std::enable_if
is using Size
for checking, but it's the template parameter of class template A
, but not template parameter of the inner template B
itself. If you add one as F
does, then it'll work. E.g.
template <int Size>
struct A {
template <int S = Size, typename T = void, typename Enable = void> struct B;
template <int S> struct B<S, bool, std::enable_if_t<S >= 1>> {};
template <int S> struct B<S, short, std::enable_if_t<S >= 2>> {};
};
D
It seems to be a gcc's issue, according to CWG 727, explicit specialization may be declared in any scope, including in class definition.
An explicit specialization may be declared in any scope in which the corresponding primary template may be defined (10.3.1.2 [namespace.memdef], 12.2 [class.mem], 17.6.2 [temp.mem]).