Каков правильный синтаксис для полной специализации класса шаблона по уже определенной специализации?
Например, как в приведенном ниже коде объявить A<2>
псевдонимом 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'
Примечание: для приведенного выше кода было бы достаточно специализировать A<1>
и определить неспециализированные A
как A<0>
:
template <int I>
struct A { int x; };
template <>
struct A<1> { int y; };
но это не сработает, если у вас более сложная ситуация, когда для набора значений у вас есть специализация, для другого набора значений другая специализация и т. д.
@463035818_is_not_a_number да, я бы хотел A<2>
быть именно A<0>
@ 463035818_is_not_a_number Теперь, когда я подумал об этом, я думаю, что мог бы сначала определить структуры, реализующие нужные мне специализации, а затем переключить значения параметра шаблона, как в этом ответе
@francsesco да, в основном это так. Разница только в деталях, как вы можете видеть в ответах
Не уверен, что понял вашу проблему, так как вы описали ее своей попыткой решить.
Вот мой подход к достижению аналогичного результата:
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
Версия с использованием типажей короче:
#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>>;
более сложная ситуация, когда для набора значений у вас есть специализация, для другого набора значений другая специализация и т.д...
Здесь может помочь уровень косвенности.
#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>
и Foo<2>
одного типа. Вы можете добавить больше специализаций в Foo_impl
и добавить больше сопоставлений между аргументом шаблона I
и фактическим индексом специализации J
.
Другие ответы должны работать, я просто хотел предложить решение на основе SFINAE:
#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;
}
Предостережение: хотя этот код позволяет A<0>
и A<2>
совместно использовать реализацию, они не будут идентичными типами. Например: std::is_same_v<A<0>, A<2>>
вернет true для других ответов, но false для этого.
ваш A<0>
не псевдоним для A<2>
, это два разных типа
@ 463035818_is_not_a_number хорошая мысль, я интерпретировал первое предложение в вопросе как означающее, что они просто хотят повторно использовать реализацию, а не дублировать ее. Если им нужно, чтобы это было того же типа, это не сработает. Я добавлю это как предостережение в свой ответ.
Нельзя сделать так, чтобы
struct
вдруг стал псевдонимом для какой-то специализации. Это похоже на проблему XY.