这个答案集中在问题上;
给定一个类型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_函数的内联定义。
注意: 解决方案假定/断言一个可访问的基类(即不是private 或protected)。如果基类是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...");
}