输入trait以检查某个类型是否派生自类模板

时间:2016-04-14 20:03:26

标签: c++ templates c++14 typetraits c++17

请考虑以下代码段:

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取决于DF来自c<F, B>

1 个答案:

答案 0 :(得分:3)

这个答案集中在这个问题上;

  

如果类型为F,我该如何检查某些类型B是否F来自c<F, B>

澄清的评论;

  

该特征应该检查某些F c<F, B>是否来自B(而B是什么并不重要。)

可以使用两个constexpr函数来“吸引”并将基础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_函数中不需要的内联定义。

注意:解决方案假定/断言可访问的基类(即不是privateprotected)。如果基类是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...");
}