我最近一直在学习c++中的SFINAE概念,目前我正在尝试在一个项目中使用它。
问题是,我想做的事情和我能找到的任何事情都不一样,我不知道该怎么做。
假设我有一个模板类叫做mypparent:template <typename Elem>
class MyParent;
和一个名为MyClass的非模板类,它继承了它,使用char作为元素:
class MyClass : public MyParent<char>;
现在,我想使用SFINAE来检查一个typename是否继承了MyParent
,而不管使用了什么Elem
类型。
我不能使用std::is_base_of
,因为父模板。
我已经试着做了以下事情:
template <typename T>
struct is_my_parent : std::false_type {};
template <typename Elem>
struct is_my_parent<MyParent<Elem>> : std::true_type {};
现在,如果我检查is_my_parent<MyParent<Elem>>::value
,它给我true
。这很好。然而,当我检查is_my_parent<MyClass>::value
时,我收到false
。这是有道理的,因为MyClass
实际上不是MyParent<Elem>
,但我没有设法得到我想要的。
除了为每个继承自MyParent
的类定义is_my_parent
之外,在c++中有什么方便的方法来实现这样的事情吗?
你可以这样做
template <typename T>
std::true_type is_my_parent_impl(const MyParent<T>*);
std::false_type is_my_parent_impl(const void*);
template <typename T>
using is_my_parent = decltype(is_my_parent_impl(std::declval<T*>()));
演示是否有任何方便的方法来实现这样的事情在c++中,除了定义is_my_parent的每一个类,从mypparent继承?
有,但是您需要使用更复杂的元编程技术。可以说,完全回归基本。
template <class C>
class is_my_parent {
using yes = char;
using no = char[2];
template<typename t>
static yes& check(MyParent<t> const*);
static no& check(...);
public:
enum { value = (1 == sizeof check(static_cast<C*>(0))) };
};
依赖于函数重载和模板的两个基本属性:
- 派生类可以用来匹配接受基类模板作为参数的函数模板。
- 省略号提供的转换序列总是被认为比其他任何转换序列都差。
然后只需检查所选重载的返回类型来确定得到的结果。除了类型别名,您甚至可以在c++ 03中使用它。或者您可以使它现代化,只要过载解析为您工作,检查将完全相同地执行。
我更喜欢Jarod42的答案,但实际的SNINAE方法与您的尝试有些接近,可以工作。这是我想到的。
要使用type_traits来回答这个问题,我们需要知道元素的类型。我们可以让MyParent
显示它:
template <typename Elem>
class MyParent {
public:
using ElemType = Elem;
};
默认的(false)is_my_parent
接受一个额外的参数,void_t
技术*可以使用:
template <typename T, typename = void>
struct is_my_parent : std::false_type {};
template <typename T>
struct is_my_parent<T, std::void_t<typename T::ElemType>> :
std::is_base_of<MyParent<typename T::ElemType>, T>::type {};
专门化只有在ElemType是T中的可访问类型时才有效,如果继承关系成立,则产生std::true|false类型。
实例:https://godbolt.org/z/na5637Knd
但是,函数重载解析不仅在简单性和大小方面是一种更好的方法,而且它还可以更快地编译。
(*) void_t是在Walter Brown 2014年的精彩的两部分演讲中向世界展示的。即使只是为了回顾也推荐。https://www.youtube.com/watch?v=Am2is2QCvxY