(SFINAE)C++检查成员函数是否存在

1.什么是SFINAE?

请看下面的链接 SFINAE


2.如果使用SFINAE检查类或者结构体是否定义某个成员函数?

这里直接给出代码,以operator()函数为例

#include 
#include 
struct Hello
{
    void operator()() { std::cout << "Hello World" << std::endl; }
};
struct Generic {};
#define HAS_MEM_FUNC(FunctionName, HelperClassName) \
    template \
struct HelperClassName { \
    typedef char one; \
    typedef long two; \
    template  static one test(decltype(&C::FunctionName)); \
    template  static two test(...); \
public: \
enum { value = sizeof(test(0)) == sizeof(char) }; \
}

HAS_MEM_FUNC(operator(), hasOperatorParentheses);

template
class A
{
public:
    static const bool value = false;
    static void execute(const typename std::decay::type & t){ std::cout << "no function to call" << std::endl; }
};
template
class A ::value >::type >
{
public:
    static const bool value = true;
    static void execute(const typename std::decay::type & t){ const_cast::type&>(t)(); }
};
int main(int argc, char *argv[])
{
    // Hello hello;
    //Generic gen;
    A::execute(Hello());
    A::execute(Generic());
    return 0;
}

3.代码解释

#define HAS_MEM_FUNC(FunctionName, HelperClassName) \
template \
struct HelperClassName { \
typedef char one; \
typedef long two; \
template  static one test( decltype(&C::FunctionName)); \
template  static two test( ...); \
public: \
enum { value = sizeof(test(0)) == sizeof(char) }; \
}
这是第一次使用SFINAE的地方,编译器在选择模板时选择匹配最佳的来生成代码。

对于未知类型T,如果T存在符合条件的成员函数,则one test函数会被编译器选择,否则编译器会选择two test,没有其他更好选择的最后选择。

并且当编译器无法使用one test而选择two test时,并不会产生编译错误。

上述代码用宏包装了一下,这样可以方便代码再次利用,而不用copy paste。


template
class A {
public:
static const bool value = false;
static void execute(const typename std::decay::type & t){ std::cout<<"no function to call"<
class A ::value >::type > {
public:
static const bool value = true;
static void execute(const typename std::decay::type & t){ const_cast::type&>(t)();}
};
这是第二次使用SFINAE的地方,某些使用我们可以能会想写出如下代码(伪代码)

if(sometype has specified member function)
{ 
	call member function
}else
{
	handle error
}

但是我们不能这样做,因为编译器会做类型检查,即便那段代码不执行。所以假设sometype没有specfied member,if条件里面的代码无法编译。

引入A 模板的意义在于,使用类模板偏特化 和 enable if 进行代码的选择编译,这样保持了接口的统一,亦可产生不同行为。

这里使用std::decay是一个奇技淫巧,是为了函数接收左值也接收右值,并且不会发生copy。没有其他特别的用途,可以不使用。



你可能感兴趣的:(C/C++)