类型特征以检查某些类型是否派生自 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>());
}
如果我们删除 constexpr
,我们也可以删除不需要的 check_base_
函数的内联定义。
注意: 解决方案 assumes/asserts 一个可访问的基础 class(即不是 private
或 protected
)。如果基 class 是 private
,上面的代码将无法编译,并出现可访问性错误。下面的代码不会失败,SFINAE 完成后可以继续编译。
#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...");
}
请考虑以下代码片段:
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 typeB
such thatF
is derived fromc<F, B>
?
为了清楚起见,还有评论;
The trait should check if
F
is derived fromc<F, B>
for someB
(and it's not important whatB
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>());
}
如果我们删除 constexpr
,我们也可以删除不需要的 check_base_
函数的内联定义。
注意: 解决方案 assumes/asserts 一个可访问的基础 class(即不是 private
或 protected
)。如果基 class 是 private
,上面的代码将无法编译,并出现可访问性错误。下面的代码不会失败,SFINAE 完成后可以继续编译。
#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...");
}