If you want to avoid manual type recursion, std::common_type
appears to me to be the only utility in the STL which is a variadic template, and hence the only one which could potentially encapsulate recursion.
Solution 1
std::common_type
finds the least-derived type in a set of types. If we identify numbers with types, specifically high numbers with less-derived types, it finds the greatest number in a set. Then, we have to map equality to the key type onto a level of derivation.
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 };
};
Solution 2
We can hack common_type
a little more. The standard says
A program may specialize this trait if
at least one template parameter in the
specialization is a user-defined type.
and describes exactly what is inside it: a recursive partial specialization case, a case which applies a binary operator, and a terminal case. Essentially, it's a generic zip
function, and you can add whatever binary operation you please. Here I used addition because it's more informative than OR. Note that is_same
returns an 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 > {};