正在检查成员是否存在,可能在基类C++11版本中
Checking a member exists, possibly in a base class, C++11 version
Inhttps://stackoverflow.com/a/1967183/134841,提供了一种静态检查成员是否存在的解决方案,可能存在于类型的子类中:
template <typename Type>
class has_resize_method
{
class yes { char m;};
class no { yes m[2];};
struct BaseMixin
{
void resize(int){}
};
struct Base : public Type, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<void (BaseMixin::*)(), &U::foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
然而,它在C++11final
类上不起作用,因为它继承了final
所阻止的被测类。
OTOH,这个:
template <typename C>
struct has_reserve_method {
private:
struct No {};
struct Yes { No no[2]; };
template <typename T, typename I, void(T::*)(I) > struct sfinae {};
template <typename T> static No check( ... );
template <typename T> static Yes check( sfinae<T,int, &T::reserve> * );
template <typename T> static Yes check( sfinae<T,size_t,&T::reserve> * );
public:
static const bool value = sizeof( check<C>(0) ) == sizeof( Yes ) ;
};
在基类中找不到reserve(int/size_t)
方法。
这个元函数的实现是否既在T
的基类中找到reserved()
,又在T
是final
的情况下仍然有效?
事实上,由于decltype
和后期返回绑定机制,C++11中的工作变得容易多了。
现在,使用测试方法更简单:
// Culled by SFINAE if reserve does not exist or is not accessible
template <typename T>
constexpr auto has_reserve_method(T& t) -> decltype(t.reserve(0), bool()) {
return true;
}
// Used as fallback when SFINAE culls the template method
constexpr bool has_reserve_method(...) { return false; }
然后您可以在类中使用它,例如:
template <typename T, bool b>
struct Reserver {
static void apply(T& t, size_t n) { t.reserve(n); }
};
template <typename T>
struct Reserver <T, false> {
static void apply(T& t, size_t n) {}
};
你这样使用它:
template <typename T>
bool reserve(T& t, size_t n) {
Reserver<T, has_reserve_method(t)>::apply(t, n);
return has_reserve_method(t);
}
或者您可以选择enable_if
方法:
template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<has_reserve_method(t), bool>::type {
t.reserve(n);
return true;
}
template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<not has_reserve_method(t), bool>::type {
return false;
}
请注意,这种切换实际上并不那么容易。一般来说,当只存在SFINAE时会容易得多——并且您只想enable_if
一种方法,而不提供任何回退:
template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
t.reserve(n);
}
如果替换失败,此方法将从可能的重载列表中删除。
注意:由于,
(逗号运算符)的语义,您可以在decltype
中链接多个表达式,并且只有最后一个表达式真正决定类型。方便检查多个操作
一个版本,它也依赖于decltype
,但不依赖于向(...)
传递任意类型[无论如何,这实际上都不是问题,请参阅Johannes的评论]:
template<typename> struct Void { typedef void type; };
template<typename T, typename Sfinae = void>
struct has_reserve: std::false_type {};
template<typename T>
struct has_reserve<
T
, typename Void<
decltype( std::declval<T&>().reserve(0) )
>::type
>: std::true_type {};
我想指出的是,根据这个特性,像std::vector<int>&
这样的类型确实支持reserve
:这里检查表达式,而不是类型。这个特征回答的问题是"给定这样一个类型T
的左值lval
,表达式lval.reserve(0);
是否形成良好"。与问题"此类型或其任何基类型是否声明了reserve
成员"不同。
另一方面,可以说这是一个特点!请记住,新的C++11特性的样式是is_default_constructible
,而不是has_default_constructor
。这种区别很微妙,但也有优点。(找到一个更适合is_*ible
风格的名字作为练习。)
在任何情况下,你仍然可以使用std::is_class
这样的特质来实现你想要的。
- 继承:构造函数,初始化C++11中基类的类C数组成员
- C++11: 如何访问派生类中的基类成员?
- C++11:我可以显式调用基类析构函数来销毁派生类吗
- 假设 C++11 中已知子级布局,重新插入基类是否安全
- 如何优雅地检查模板类型是否来自C 11中的特定基类
- C++11可变参数模板方法完全影子基类方法
- 子类对象列表重新解释为基类对象列表?(C++11).
- 为什么我的一个基类构造函数被删除了?(C++11).
- 为什么 C++11 中仍然需要 "using" 指令来从派生类中重载的基类中引入方法
- C++11 非模板化基类中的纯虚拟'templated'返回类型
- C++11:使用中央命令映射器调用虚拟基类方法
- C++11 指向同一基类的其他类的指针的非静态数据成员统一初始化失败
- 在 C++11 中,是否可以将 ref'ed 基类传递给线程的构造函数并获得多态行为?
- 正在检查成员是否存在,可能在基类C++11版本中
- 在C++11中显式删除了成员函数后,从不可编译的基类继承是否仍然值得
- 防止重写和/或隐藏基类函数(C++11)
- 带有混合虚基和非虚基的c++ 11类格
- 当基类具有两个或多个模板参数时,C++11 别名基模板类变量在模板派生类中不起作用
- 重写 C++11 中的<<运算符、基类中的纯虚拟以及每个派生类中的不同实现
- 使用C++11线程基类