Специализация классов группового класса
Существует ли метод/лучший стиль для группировки специализированных шаблонов классов для определенных типов?
Пример: Допустим, у меня есть шаблон класса Foo
, и мне нужно, чтобы он специализировался на наборе
A = { Line, Ray }
и другим способом для набора B
B = { Linestring, Curve }
Что я делаю до сих пор: (техника также представлена здесь для функций)
#include <iostream>
#include <type_traits>
using namespace std;
// 1st group
struct Line {};
struct Ray {};
// 2nd group
struct Curve {};
struct Linestring {};
template<typename T, typename Groupper=void>
struct Foo
{ enum { val = 0 }; };
// specialization for the 1st group
template<typename T>
struct Foo<T, typename enable_if<
is_same<T, Line>::value ||
is_same<T, Ray>::value
>::type>
{
enum { val = 1 };
};
// specialization for the 2nd group
template<typename T>
struct Foo<T, typename enable_if<
is_same<T, Curve>::value ||
is_same<T, Linestring>::value
>::type>
{
enum { val = 2 };
};
int main()
{
cout << Foo<Line>::val << endl;
cout << Foo<Curve>::val << endl;
return 0;
}
Дополнительная вспомогательная структура enable_for
сократит код (и позволит напрямую писать принятые типы). Любые другие предложения, исправления? Разве это не требует меньших усилий?
Ответы
Ответ 1
Вы также можете сделать это со своими собственными чертами и без enable_if
:
// Traits
template <class T>
struct group_number : std::integral_constant<int, 0> {};
template <>
struct group_number<Line> : std::integral_constant<int, 1> {};
template <>
struct group_number<Ray> : std::integral_constant<int, 1> {};
template <>
struct group_number<Linestring> : std::integral_constant<int, 2> {};
template <>
struct group_number<Curve> : std::integral_constant<int, 2> {};
// Foo
template <class T, int Group = group_number<T>::value>
class Foo
{
//::: whatever
};
template <class T>
class Foo<T, 1>
{
//::: whatever for group 1
};
template <class T>
class Foo<T, 2>
{
//::: whatever for group 2
};
Это имеет преимущество автоматического обеспечения того, чтобы каждый тип был не более одной группы.
Ответ 2
Дополнительный уровень косвенности с использованием двух новых типов:
template<class T>
struct is_from_group1: std::false_type {};
template<>
struct is_from_group1<Line>: std::true_type {};
template<>
struct is_from_group1<Ray>: std::true_type {};
template<class T>
struct is_from_group2: std::false_type {};
template<>
struct is_from_group2<Curve>: std::true_type {};
template<>
struct is_from_group2<Linestring>: std::true_type {};
а затем enable_if
на этих типах признаков
// specialization for the 1st group
template<typename T>
struct Foo<T, typename enable_if<
is_from_group1<T>::value
>::type>
{
enum { val = 1 };
};
// specialization for the 2nd group
template<typename T>
struct Foo<T, typename enable_if<
is_from_group2<T>::value
>::type>
{
enum { val = 2 };
};
Обратите внимание, что вам все равно нужно убедиться, что ни один пользовательский класс не добавлен к обеим группам, или вы получите двусмысленность. Вы можете использовать решение @Angew для получения из пронумерованной группы, используя std::integral_constant<int, N>
для номера группы N
. Или, если эти группы не являются логически исключительными, вы можете добавить дополнительное условие внутри enable_if
, которое защищает от этого.