I have a type trait that checks if a given type is an instance of a given class template:
template <template <typename...> class C, typename T>
struct check_is_instance_of : std::false_type { };
template <template <typename...> class C, typename ...Ts>
struct check_is_instance_of<C, C<Ts...>> : std::true_type { };
template <template <typename...> class C, typename T>
struct is_instance_of : check_is_instance_of<C, std::remove_cv_t<T>> { };
Unfortunately, this does not work for non-type template parameters as they are not "captured" by the variadic template parameters, so
is_instance_of<std::integral_constant, std::true_type>
yields a compile-error. Is there any way to write an implementation of is_instance_of
that works for an arbitrary number of type and non-type template parameters?
I don't think there is a clean way to do this unless the non-type arguments are all of the same type and you know which type it is. In that very specific case, function overloading can be used.
In any other case, you end up in a template-argument version of the perfect forwarding problem where you would have to specialize for every type/nontype argument combination.
If you only need to address homogeneous non-template arguments and you can guess the type, the following should work. You can overload instance_of for different types (only int is covered here), but you'd have to explicitly create an instance for each type you want to be able to handle:
// variation for non-type parameters, only for uniform parameters with
// known type.
template <typename V, template <V...> class C, typename T>
struct check_is_instance_of_nontype : std::false_type { };
template <typename V, template <V...> class C, V... Values>
struct check_is_instance_of_nontype<V, C, C<Values...>> : std::true_type { };
// this is as in your example
template <template <typename...> class C, typename T>
struct check_is_instance_of : std::false_type { };
template <template <typename...> class C, typename ...Ts>
struct check_is_instance_of<C, C<Ts...>> : std::true_type { };
template <template <typename...> class C, typename T>
struct is_instance_of : check_is_instance_of<C, std::remove_cv_t<T>> { };
template <template <typename...> class C, typename T>
constexpr bool instance_of()
{
return is_instance_of< C, T>::value;
}
template <template <int...> class C, typename T>
constexpr bool instance_of()
{
return check_is_instance_of_nontype< int, C, T>::value;
}
template< int... >
struct Duck
{
};
template<typename A, typename B>
struct Swallow
{
};
int main() {
typedef Duck<1, 2> SittingDuck;
typedef Swallow< int, int> UnladenSwallow;
std::cout << instance_of< Duck, SittingDuck>() << instance_of< Swallow, UnladenSwallow>();
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With