C++ 检查成员是否存在,可能在基类C++;11版本
在中,提供了一种解决方案,用于静态检查成员是否存在,可能存在于类型的子类中:C++ 检查成员是否存在,可能在基类C++;11版本,c++,c++11,final,template-meta-programming,typetraits,C++,C++11,Final,Template Meta Programming,Typetraits,在中,提供了一种解决方案,用于静态检查成员是否存在,可能存在于类型的子类中: 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 Bas
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)));
};
在基类中找不到保留(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; }
注意,这种切换实际上并不容易。一般来说,只有SFINAE存在时会容易得多——您只想启用\u if
一种方法,而不提供任何回退:
template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
t.reserve(n);
}
模板
自动保留(T&T,size\u T n)->decltype(T.reserve(n),void()){
t、 储备(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 {};
模板结构Void{typedef Void type;};
模板
结构具有_保留:std::false_类型{};
模板
结构具有\u保留<
T
,typename Void<
decltype(std::declval().reserve(0))
>::类型
>:std::true_type{};
我想指出,根据这一特点,一种类型,如std::vector&
确实支持reserve
:这里检查的是表达式,而不是类型。这个特征回答的问题是“对于这种类型的T
,给定一个左值lval
,表达式lval.reserve(0);
格式良好”。与问题“此类型或其任何基本类型是否声明了保留
成员”不同
另一方面,可以说这是一个特性!请记住,新的C++11 trait的样式是是默认的\u可构造的
,而不是具有默认的\u构造函数
。这种区别是微妙的,但也有优点。(在样式中找到一个更合适的名称是一个练习。)
在任何情况下,您仍然可以使用诸如std::is_class
之类的特性来实现您想要的目标。在C++11上,您可以使用“sfinae for expressions”,而不是使用C++03中所需的这种迂回方式。@johanneschaub litb请求解决方案!我很想看看它对此类示例的不同之处。t
是否需要是文本类型才能成为constepr
函数的参数?好的,在模板上,constepr
在实例化时会被删除,因为它不能是constepr
,但是您在模板参数列表中使用它,它必须在模板参数列表中。@MarcMutz-mmutz:为了避免创建空指针,您可以使用std::declval()
,它将返回一个t
(如果愿意,您可以将其与T const&
一起使用)。传递一个不足以(…)
的类类型不是一个好主意(例如,它是有条件支持的)。我仍然更喜欢使用未赋值表达式的传统方式。@Luc我想你可以用另一种方式来看待它:他只做函数调用替换。这样的事情将函数调用表达式转换成另一个表达式,而不必再做函数调用。最后他得到了表达式false
.未来编辑注意:我使用了来自的筛选(而不是“调用”)。
template <typename T>
bool reserve(T& t, size_t n) {
Reserver<T, has_reserve_method(t)>::apply(t, n);
return has_reserve_method(t);
}
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;
}
template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
t.reserve(n);
}
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 {};