If you can assume that a derived type uses a public inheritance from B<Args...>
(and so the upcasting is possible), then you can use the following SFINAE:
namespace detail
{
template <typename Derived>
struct is_derived_from_B
{
using U = typename std::remove_cv<
typename std::remove_reference<Derived>::type
>::type;
template <typename... Args>
static auto test(B<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, B<Args...>>::value>;
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
}
template <typename Derived>
using is_derived_from_B = typename detail::is_derived_from_B<Derived>::type;
Tests:
static_assert(is_derived_from_B<const D<int, char, float>>::value, "!");
static_assert(!is_derived_from_B<int>::value, "!");
static_assert(!is_derived_from_B<B<int,int>>::value, "!");
static_assert(!is_derived_from_B<std::vector<int>>::value, "!");
DEMO 1
It can be generalized to accept any base class template:
namespace detail
{
template <template <typename...> class Base, typename Derived>
struct is_derived_from_template
{
using U = typename std::remove_cv<
typename std::remove_reference<Derived>::type
>::type;
template <typename... Args>
static auto test(Base<Args...>*)
-> typename std::integral_constant<bool
, !std::is_same<U, Base<Args...>>::value>;
static std::false_type test(void*);
using type = decltype(test(std::declval<U*>()));
};
}
template <template <typename...> class Base, typename Derived>
using is_derived_from_template
= typename detail::is_derived_from_template<Base, Derived>::type;
Tests:
static_assert(is_derived_from_template<B, const D<int, int>>::value, "!");
static_assert(!is_derived_from_template<B, int>::value, "!");
static_assert(!is_derived_from_template<B, B<int, int>>::value, "!");
static_assert(!is_derived_from_template<B, std::vector<int>>::value, "!");
DEMO 2
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…