What is the correct syntax to fully specialize a template class, to an already defined specialization?
E.g., in the code below, how can I declare A<2>
as an alias to A<0>
?
template <int I>
struct A;
template <>
struct A<0> { int x; };
template <>
struct A<1> { int y; };
template <>
using A<2> = A<0>; // error: expected unqualified-id before 'using'
Note: for the code above, it would be enough to specialize A<1>
and define the non-specialized A
like A<0>
:
template <int I>
struct A { int x; };
template <>
struct A<1> { int y; };
but this would not work if you a more complex situation, where for a set of values you have a specialization, for another set of values another specialization, etc...
CodePudding user response:
Not sure I understood your problem, since you described it by your attempt to solve it.
Here is my approach to achieve similar result:
struct Ax { int x; };
struct Ay { int y; };
template <int I>
struct Aselector;
template<>
struct Aselector<0>{
using type = Ax;
};
template<>
struct Aselector<1>{
using type = Ay;
};
template<>
struct Aselector<2>{
using type = Ax;
};
template <int I>
using A = typename Aselector<I>::type;
https://godbolt.org/z/fGxcoE5xd
Version using type traits is shorter:
#include <type_traits>
struct Ax { int x; };
struct Ay { int y; };
template <int I>
using A = std::conditional_t<I == 1, Ay, std::enable_if_t<I >= 0 && I <= 2, Ax>>;
https://godbolt.org/z/vMqPahfEo
CodePudding user response:
more complex situation, where for a set of values you have a specialization, for another set of values another specialization, etc...
A level of indirection can help here.
#include <iostream>
#include <type_traits>
template <size_t I> struct selector { static const size_t value = I; };
template <> struct selector<2> { static const size_t value = 0;};
template <size_t J> struct Foo_impl { int x; };
template <> struct Foo_impl<1> { int y; };
template <size_t I> using Foo = Foo_impl< selector<I>::value >;
int main() {
std::cout << std::is_same_v< Foo<0> , Foo<2> > << "\n";
Foo<0> f0;
f0.x = 42;
Foo<1> f1;
f1.y = 0;
Foo<2> f2;
f2.x = 123;
}
Foo<0>
and Foo<2>
are the same type. You can add more specializations to Foo_impl
and you can add more mapping between the template argument I
and actual index of specialization J
.
CodePudding user response:
The other answers should work, I just wanted to offer a SFINAE based solution:
#include <iostream>
template <int I, typename = void>
struct A;
template <int I>
struct A<I, std::enable_if_t<I == 0 || I == 2>> { int x; };
template <typename Conditional>
struct A<1, Conditional> { int y; };
int main()
{
std::cout << A<0>{}.x << std::endl;
std::cout << A<1>{}.y << std::endl;
std::cout << A<2>{}.x << std::endl;
return 0;
}
Caveat: while this code allows A<0>
and A<2>
to share an implementation, they will not be identical types. Eg: std::is_same_v<A<0>, A<2>>
will return true for the other answers, but false for this one.