C++ SFINAE方法比较
下面的代码显示了一个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<
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)};
};