Pra*_*rav 6 c++ templates sfinae
以下代码显示了SFINAE实现,以检查类型(基本上是类)是否member_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
}
Run Code Online (Sandbox Code Playgroud)
但是我的问题是你更喜欢哪种方法(APPROACH 1或APPROACH 2)以及为什么?
您是否发现给定方法存在任何不一致之处?如果是,请告诉我.
PS:假设 sizeof(char)!= sizeof(long)
Ale*_* C. -1
编辑:已完成并更正。
另一种方法,使用继承的歧义,在功能上可能与方法 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;
};
Run Code Online (Sandbox Code Playgroud)
当 T 是类时,这有效,因此您可能需要添加图层来检查 T 是否是类类型。
请注意,任何foo成员函数都会被检测到。如果要检查是否foo可以使用给定参数调用检测到的函数,则必须执行另一层 SFINAE:
// Check whether foo can be called with an argument of type Arg
// and yields an element of type Res.
// If you need Res = void, this code does not work.
template <class T, typename Arg, typename Res>
struct check_foo
{
struct flag {};
struct D : T { using T::foo; flag foo(...); };
template <typename U>
static char (&test(U))[1];
template <typename> static char (&test(...))[2];
static Arg f();
static const bool value = sizeof(test<Arg>( ((D*)0)->foo(f()) )) == 1;
};
Run Code Online (Sandbox Code Playgroud)