Reputation: 69
For the following code:
template <typename T>
struct IsOneOf<T,T> { const static bool True = true; };
template <typename T, typename ... Ts>
struct IsOneOf<T,any_of<T,Ts ...> > { const static bool True = true;};
template <typename T, typename T2,typename ... Ts>
struct IsOneOf<T,any_of<T2,Ts ...> > {
const static bool True = IsOneOf<T,T2>::True ||
IsOneOf<T,any_of<Ts ...> >::True;
};
template <typename T1, typename ... Ts1, typename ... Ts2>
struct IsOneOf< any_of<T1,Ts1 ...>, any_of<Ts2 ...> > {
const static bool True = IsOneOf<T1,any_of<Ts2 ...> >::True &&
IsOneOf<any_of<Ts1...>, any_of<Ts2 ...> >::True;
};
The last specialization is intended to override the others, but I receive ambiguous template instantiation errors for IsOneOf<any_of<int>,any_of<int,double,float>>::True
. Can someone suggest a way to overcome this?
Upvotes: 2
Views: 141
Reputation: 45434
What's the point of this complicated and opaque design? If the idea was that IsOneOf<A,B...>::value
is true
if and only if at least one of the B
types is the same as A
, then a simple recursive design (avoiding auxiliaries such as any_of
) such as
// is_one_of<A,B1,B2,...>::value == is_same<A,B1>::value || is_same<A,B2>::value ...
template<typename A, typename... B>
struct is_one_of;
// case of empty pack B...
template<typename A>
struct is_one_of<A> : std::false_type {};
// general case: recurse
template<typename A, typename B1, typename... B>
struct is_one_of<A,B1,B...>
: std::integral_constant<bool, std::is_same<A,B1>::value || is_one_of<A,B...>::value> {};
is preferrable, requiring only two specialisations (for an empty pack of B
s and the recursive case). Moreover, is_one_of
are good C++ citizens by being derived from std::integral_constant<bool,C>
.
Upvotes: 0
Reputation: 72356
The last specialization IsOneOf<any_of<T1,Ts1...>, any_of<Ts2...>>
is not more specialized than IsOneOf<T,any_of<T2,Ts...>>
because if Ts2
is an empty list, it can't match the latter. I think you want this, either in place of or in addition to your last specialization:
template <typename T1, typename ... Ts1, typename T2, typename ... Ts2>
struct IsOneOf< any_of<T1,Ts1 ...>, any_of<T2,Ts2 ...> >
{
const static bool True = IsOneOf<T1, any_of<T2,Ts2...>>::True &&
IsOneOf<any_of<Ts1...>, anyOf<T2,Ts2...>>::True;
};
You would also have a problem with IsOneOf<any_of<int,double>, any_of<int,double>>
since in that case your IsOneOf<T,T>
is ambiguous with this general case. So you can cut that off by specifying the intersection:
template <typename T1, typename ... Ts>
struct IsOneOf< any_of<T1,Ts ...>, any_of<T1,Ts ...> >
{
const static bool True = true;
};
You will also need base cases dealing with the type any_of<>
, if you don't already have them.
Upvotes: 1