Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 检查成员是否存在,可能在基类C++;11版本_C++_C++11_Final_Template Meta Programming_Typetraits - Fatal编程技术网

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 {};