类型特征以检查某些类型是否派生自 class 模板

Type trait to check whether some type is derived from a class template

请考虑以下代码片段:

template<class A, class B>
class c {};

template<class D>
class e
    : public c<e<D>, /* some type depending on D */>
{ }

给定类型 F,我如何检查是否有某种类型 B 使得 F 派生自 c<F, B>

示例:对于 F = e<D>,有一些类型 B 取决于 D,因此 F 派生自 c<F, B>

本回答重点关注问题;

Given a type F, how can I check whether there is some type B such that F is derived from c<F, B>?

为了清楚起见,还有评论;

The trait should check if F is derived from c<F, B> for some B (and it's not important what B is).

两个 constexpr 函数可用于 "attract" 并将基数 c<F, B> 与其他类型区分开来。 函数模板受到青睐,因为它们能够deduce types(这需要满足一些B的要求) .形式如下...

template <typename F, typename B>
constexpr bool check_base(C<F, B> &&) { return true; }

template <typename F>
constexpr bool check_base(...) { return false; }

以下示例在改进的使用场景中说明了基本工作原理;

#include <utility>
template <typename A, typename B>
struct C {};

template <typename F, typename B>
constexpr std::true_type check_base_(C<F, B>&&) { return {}; }

template <typename F>
constexpr std::false_type check_base_(...) { return {}; }

template <typename T>
using check_base = decltype(check_base_<T>(std::declval<T>()));

template <typename D>
struct E : C<E<D>, D> {};
struct FailF {};

int main()
{
    static_assert(check_base<E<int>>());
    static_assert(!check_base<FailF>());
}

See the demo here.

如果我们删除 constexpr,我们也可以删除不需要的 check_base_ 函数的内联定义。

注意: 解决方案 assumes/asserts 一个可访问的基础 class(即不是 privateprotected)。如果基 class 是 private,上面的代码将无法编译,并出现可访问性错误。下面的代码不会失败,SFINAE 完成后可以继续编译。

Online demo here.

#include <utility>
#include <type_traits>
template <typename A, typename B>
struct C {};

template <typename F, typename B>
std::true_type check_base_(C<F, B>&&, typename std::enable_if<std::is_convertible<F, C<F,B>>::value>::type* = nullptr);

template <typename F>
std::false_type check_base_(...);

template <typename T>
using check_base = decltype(check_base_<T>(std::declval<T>()));

template <typename D>
struct Example : C<Example<D>, D> {};
struct CtorTest : C<CtorTest, int> { CtorTest(int, int) {} };
struct PrivateBase : private C<PrivateBase, double> {};
struct FailTest {};

int main()
{
    static_assert(check_base<Example<int>>(), "fail...");
    static_assert(check_base<CtorTest>::value, "fail...");
    static_assert(!check_base<PrivateBase>(), "fail...");
    static_assert(!check_base<FailTest>(), "fail...");
}