Если вы хотите избежать ручной рекурсии типа, std::common_type
представляется мне единственной утилитой в STL, которая представляет собой шаблон с переменными числами, и, следовательно, единственной, которая потенциально может инкапсулировать рекурсию.
Раствор 1
std::common_type
находит наименее производный тип в наборе типов. Если мы отождествляем числа с типами, особенно большие числа с менее производными типами, он находит наибольшее число в наборе. Затем мы должны сопоставить равенство с типом ключа на уровне деривации.
using namespace std;
struct base_one { enum { value = 1 }; };
struct derived_zero : base_one { enum { value = 0 }; };
template< typename A, typename B >
struct type_equal {
typedef derived_zero type;
};
template< typename A >
struct type_equal< A, A > {
typedef base_one type;
};
template< typename Key, typename ... Types >
struct pack_any {
enum { value =
common_type< typename type_equal< Key, Types >::type ... >::type::value };
};
Решение 2
Мы можем взломать common_type
еще немного. Стандарт гласит
Программа может специализировать эту черту, если
по крайней мере, один параметр шаблона в
специализация - это пользовательский тип.
и точно описывает, что внутри него: случай рекурсивной частичной специализации, случай, в котором применяется бинарный оператор, и случай терминала. По сути, это общая функция fold
, и вы можете добавить любую бинарную операцию, какую пожелаете. Здесь я использовал дополнение, потому что оно более информативно, чем OR. Обратите внимание, что is_same
возвращает integral_constant
.
template< typename Addend >
struct type_sum { // need to define a dummy type to turn common_type into a sum
typedef Addend type;
};
namespace std { // allowed to specialize this particular template
template< typename LHS, typename RHS >
struct common_type< type_sum< LHS >, type_sum< RHS > > {
typedef type_sum< integral_constant< int,
LHS::type::value + RHS::type::value > > type; // <= addition here
};
}
template< typename Key, typename ... Types >
struct pack_count : integral_constant< int,
common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {};