Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.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++ SFINAE方法比较_C++_Templates_Sfinae - Fatal编程技术网

C++ SFINAE方法比较

C++ SFINAE方法比较,c++,templates,sfinae,C++,Templates,Sfinae,下面的代码显示了一个SFINAE实现,用于在编译时检查类型(基本上是类)是否包含成员函数member\u func #define CHECKER(func_name,class_name) sizeof(class_name<T>::template func_name<T>(0)) == 1 #include <iostream> struct A { void member_func(); }; struct B {}; template<

下面的代码显示了一个SFINAE实现,用于在编译时检查类型(基本上是类)是否包含成员函数
member\u func

#define CHECKER(func_name,class_name) sizeof(class_name<T>::template func_name<T>(0)) == 1
#include <iostream>
struct A
{
    void member_func();
};
struct B {};
template<typename T>struct Check_If_T_Is_Class_Type
{
    template<typename C> static char func (char C::*p);
    template<typename C> static long func (...);
    enum{val = CHECKER(func,Check_If_T_Is_Class_Type)};
};

//APPROACH 1
template <typename T>struct TypeHasMemberFunc
{
    template <typename C, C> struct TypeCheck;
    template <typename C> struct Prototype_Holder {typedef void (C::*fptr)();};
    template <typename C> static char func(TypeCheck
                                           <
                                              typename Prototype_Holder<C>::fptr,
                                              &C::member_func
                                           >*);
    template <typename C> static long func(...);
    enum {value = CHECKER(func,TypeHasMemberFunc)};
};

//APPROACH 2
template <typename T>struct has_member_func
{
    template<class C> static char func(char (*)[sizeof(&C::member_func)]);
    template<class C> static long func(...);
    enum{value = CHECKER(func,has_member_func)};
};
int main(){
 if(Check_If_T_Is_Class_Type<A>::val)
   std::cout<<TypeHasMemberFunc<A>::value; //using APPROACH 1

 if(Check_If_T_Is_Class_Type<B>::val)
   std::cout<<has_member_func<B>::value; //using APPROACH 2
}
\define CHECKER(函数名,类名)sizeof(类名::模板函数名(0))==1
#包括
结构A
{
无效成员_func();
};
结构B{};
templatestruct检查\u是否为\u类\u类型
{
模板静态字符func(字符C::*p);
模板静态长函数(…);
枚举{val=CHECKER(func,检查\u是否为\u类\u类型)};
};
//方法1
模板结构TypeHasMemberFunc
{
模板结构类型检查;
模板结构原型{typedef void(C::*fptr)(;};
模板静态字符功能(类型检查
<
typename Prototype_Holder::fptr,
&C::成员函数
>*);
模板静态长函数(…);
枚举{value=CHECKER(func,TypeHasMemberFunc)};
};
//方法2
模板结构具有_member _func
{
模板静态char func(char(*)[sizeof(&C::member_func)];
模板静态长函数(…);
枚举{value=CHECKER(func,has_member_func)};
};
int main(){
如果(检查是否为类类型::val)

标准::cout编辑:完成并更正

另一种方法是使用继承的模糊性,在功能上可能与方法2相同。我记得方法1有问题(虽然它是用G++4.4.5编译的),因为名称解析触发了一个错误,而不是替换失败。我不得不求助于:

template <class T>
struct has_foo
{
  struct fallback { void foo(...); };
  struct D : T, fallback { };

  template <typename U, U> struct K;

  // Will be ambiguous for U = D iff T has a foo member function.                                                                                                         
  // It doesn't trigger an error, since D will always have at least one                                                                                                   
  // foo member function.                                                                                                                                                 
  template <class U> static char (&test(K<void (fallback::*)(...), &U::foo>*))[1];
  template <class U> static char (&test(...))[2];

  static const bool value = sizeof(test<D>(0)) == 2;
};

第二种方法不检查函数类型(返回类型或参数类型),并且可以处理所有类型,而不仅仅是类类型。

我个人更喜欢使用第二种方法,因为它更短,更容易理解。但是GCC不会编译它,所以您必须对GCC使用类似的方法:

namespace detail
{
    template<class C> char func(char (*)[sizeof(&C::member_func)]);
    template<class C> long func(...);   
}

template <typename T>struct has_member_func
{
    enum{value = (sizeof(detail::func<T>(0)) == 1)};
};
名称空间详细信息
{
模板char func(char(*)[sizeof(&C::member_func)];
模板长函数(…);
}
模板结构具有_member _func
{
枚举{value=(sizeof(detail::func(0))==1)};
};
另外,最好去掉CHECKER宏,这会使代码的可读性大大降低

<>无论如何,我将避免在生产代码中使用这样的C++黑客(除了你是一个Boost团队成员:-)/P>
<>这类东西容易出错,难以支持,编译器之间几乎不可移植,但主要的原因是我不记得任何实际的任务需要这样的硬代码C++。

代码>所以你可能想添加另一个层来检查T是否是已经被照顾的类类型< /代码>。ype
检查类型
T
是否为类类型。@Alexandre C…你说的触发了一个简单的错误而不是替换失败,因为member_func通常不是C的成员…所以你的意思是,member_func必须是C的成员才能导致“替换失败”?这有什么意义?我相信你需要
K
?如果传递
U
,则无法传递
&U::foo
,因为它需要从
void(fallback::*)(…)
隐式转换到
void(D::*)(…)
。此外,您的代码将无法检测特定的函数类型。该代码更像是“检查该类中是否有具有给定名称的成员”。它不会只检查一个特定的成员函数。@Nawaz,@litb,edited。匆忙编写的代码现在可以工作了。Johannes你说得对,这个方法只测试具有特定名称的成员函数是否存在。我需要检查一次类是否是一个可以用给定签名调用的函数(可能需要转换)我使用了这种精确的方法,用另一种sfinae机制来检查签名。至于纯错误的事情,我记得像OP一样在拼写
foo
方面有问题,它触发了一个错误,而不是替换失败,我不得不使用继承方法。另一种方法:第二种方法在重载函数时失败。我检查ked和no,第二种方法可以在GCC中编译:-也可以参考。它有一些非常好的答案。
namespace detail
{
    template<class C> char func(char (*)[sizeof(&C::member_func)]);
    template<class C> long func(...);   
}

template <typename T>struct has_member_func
{
    enum{value = (sizeof(detail::func<T>(0)) == 1)};
};