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> оба. (понятия не имею, как!)
Проверьте
Ссылка на тестовый код