C++11 and up gives us a wealth of alternatives with which to write arbitrarily complex type traits in fairly simple fashion. One such is void_t
:
template <typename... >
using void_t = void;
All you do is write a base trait:
template <typename X, typename = void>
struct has_rebind : std::false_type { };
and then a partial specialization that will only pass template deduction if the criteria you want is met, namely that X
has a rebind<T>
. In this case, the type doesn't matter, so we can just pick one:
template <typename X>
struct has_rebind<X, void_t<typename X::template rebind<int>>>
: std::true_type { };
Demo
A different approach to the same thing is Yakk's can_apply
, which with some boilerplate:
namespace details {
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<template<class...>class Z, class, class...Ts>
struct can_apply:std::false_type{};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=details::can_apply<Z,void,Ts...>;
We can write something similar:
template <typename X, typename T>
using rebind_t = typename X::template rebind<T>;
template <typename X>
using has_rebind = can_apply<rebind_t, X, int>;
Demo 2