Std:: is_base_of для классов шаблонов

Есть ли способ проверить std::is_base_of<A, B>, когда A является классом шаблона?

template <typename X, typename Y> class A {};

template <typename X> class B : public A<X, char> {};

Я хочу статически тестировать что-то вроде std::is_base_of<A, B<int>>, значение B выводится из любой специализации A. (Чтобы сделать его более общим, скажем, мы не знаем, как B специализируется на A, т.е. B <X> выводит из A < X, char > )

Один из способов решения - вывести A из класса (не шаблон), скажем C, а затем проверить std::is_base_of<C, B<int>>. Но есть ли другой способ сделать это?

Ответ 1

Вы можете сделать следующее:

template <template <typename...> class C, typename...Ts>
std::true_type is_base_of_template_impl(const C<Ts...>*);

template <template <typename...> class C>
std::false_type is_base_of_template_impl(...);

template <typename T, template <typename...> class C>
using is_base_of_template = decltype(is_base_of_template_impl<C>(std::declval<T*>()));

Live Demo

но с множественным наследованием или частным наследованием с A не будет выполнено.

Ответ 2

Следующее решение работает с защищенным наследованием.

template <template <typename...> class BaseTemplate, typename Derived, typename TCheck = void>
struct test_base_template;

template <template <typename...> class BaseTemplate, typename Derived>
using is_base_template_of = typename test_base_template<BaseTemplate, Derived>::is_base;

//Derive - is a class. Let inherit from Derive, so it can cast to its protected parents
template <template <typename...> class BaseTemplate, typename Derived>
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<std::is_class_v<Derived>>> : Derived
{
    template<typename...T>
    static constexpr std::true_type test(BaseTemplate<T...> *);
    static constexpr std::false_type test(...);
    using is_base = decltype(test((test_base_template *) nullptr));
};

//Derive - is not a class, so it is always false_type
template <template <typename...> class BaseTemplate, typename Derived>
struct test_base_template<BaseTemplate, Derived, std::enable_if_t<!std::is_class_v<Derived>>>
{
    using is_base = std::false_type;
};

Удивительно, но на VS2017 он работает с множественным наследованием от того же шаблона, например C <int> и C <float> оба. (понятия не имею, как!)

Проверьте Ссылка на тестовый код