2

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...

francesco
  • 7,189
  • 7
  • 22
  • 49
  • 1
    You can't make `struct` suddenly to become alias for some specialization. This looks like [XY problem](https://xyproblem.info/). – Marek R Jan 13 '23 at 09:55
  • @463035818_is_not_a_number yes, I would like ```A<2>``` to be exactly a ```A<0>``` – francesco Jan 13 '23 at 09:56
  • @463035818_is_not_a_number Now that I think about it, I guess I could define first structs that implement the specializations I want, and then switch over the values of the template parameter as in [this answer](https://stackoverflow.com/a/75097423/8769985) – francesco Jan 13 '23 at 10:09
  • @francsesco yes thats basically it. Difference is only in details as you can see in the answers – 463035818_is_not_an_ai Jan 13 '23 at 10:23

3 Answers3

2

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

Marek R
  • 32,568
  • 6
  • 55
  • 140
1

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.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
0

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.

Wutz
  • 2,246
  • 13
  • 15
  • your `A<0>` is not an alias for `A<2>`, they are two different types – 463035818_is_not_an_ai Jan 13 '23 at 10:26
  • @463035818_is_not_a_number good point, I interpreted the first sentence in the question to mean they just want to re-use an implementation instead of duplicating it. If they need it to be the same type this won't work. I'll add it as a caveat into my answer. – Wutz Jan 13 '23 at 10:33