Uroc327
Uroc327

Reputation: 1429

Check if a class is equal to a template instance or a normal class

I have an integral_constant to determine if a class is in a provided list of classes:

template <typename T> using decay_t = typename std::decay<T>::type;

template <typename... Args> struct SOneOf : std::integral_constant<bool, false>
{
};

template <typename T1, typename T2, typename... Tail> struct SOneOf<T1, T2, Tail...>
    : std::integral_constant<bool, SOneOf<T1, T2>::value || SOneOf<T1, Tail...>::value>
{
};

template <typename T1, typename T2> struct SOneOf<T1, T2>
    : std::integral_constant<bool, std::is_same<decay_t<T1>, decay_t<T2>>::value>
{
};

template <typename T> struct SOneOf<T> : std::integral_constant<bool, false>
{
};

I also know that I can give templated classes as template arguments via template <template <typename> class T>.

Assuming I have two classes

template <typename T> class CClassA;
template <typename T> class CClassB;

and am in a function template <typename TF> function f().

How can I generically check if TF (e.g. int or CClassA<double>) is a CClassA or a CClassB or a float?

I'd like to achieve something like

SOneOf<TF, CClassA, CClassB, float>::value

Upvotes: 2

Views: 555

Answers (1)

Columbo
Columbo

Reputation: 61009

If you're trying to get that information inside the function template you can use partial specialization:

template <bool...> struct bool_pack;
template <bool... B>
using any_true = std::integral_constant<bool,
  !std::is_same<bool_pack<false, B...>, bool_pack<B..., false>>{}>;

namespace detail {
  template <template <class...> class, typename>
  struct IsSpec : std::false_type {};
  template <template <class...> class T, typename... U>
  struct IsSpec<T, T<U...>> : std::true_type {};
}

template <typename U, template <class...> class... T>
using IsSpecialization = any_true<detail::IsSpec<T, std::decay_t<U>>{}...>;

Usage would be simple:

static_assert( IsSpecialization<CClassB<int>, CClassA, CClassB>{}, "" );
static_assert( !IsSpecialization<void, CClassA, CClassB>{}, "" );

Demo. The extra comparison for float has to be done separately, e.g. via std:is_same.

If you need different code based on the template the type is a specialization of, use overloading.

template <typename Arg>
void f( CClassA<Arg> const& obj ) { /* … */ }
template <typename Arg>
void f( CClassB<Arg> const& obj ) { /* … */ }

Upvotes: 7

Related Questions