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

来源:互联网 发布:英雄联盟mac有国服? 编辑:程序博客网 时间:2024/05/29 07:29

1.什么是SFINAE?

请看下面的链接 SFINAE


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

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

#include <type_traits>#include <iostream>struct Hello{    void operator()() { std::cout << "Hello World" << std::endl; }};struct Generic {};#define HAS_MEM_FUNC(FunctionName, HelperClassName) \    template<typename T> \struct HelperClassName { \    typedef char one; \    typedef long two; \    template <typename C> static one test(decltype(&C::FunctionName)); \    template <typename C> static two test(...); \public: \enum { value = sizeof(test<T>(0)) == sizeof(char) }; \}HAS_MEM_FUNC(operator(), hasOperatorParentheses);template<class T, class Enable = void>class A{public:    static const bool value = false;    static void execute(const typename std::decay<T>::type & t){ std::cout << "no function to call" << std::endl; }};template<class T>class A <T, typename std::enable_if< hasOperatorParentheses<T>::value >::type >{public:    static const bool value = true;    static void execute(const typename std::decay<T>::type & t){ const_cast<typename std::decay<T>::type&>(t)(); }};int main(int argc, char *argv[]){    // Hello hello;    //Generic gen;    A<Hello>::execute(Hello());    A<Generic>::execute(Generic());    return 0;}

3.代码解释

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

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

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

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


template<class T, class Enable = void>class A {public:static const bool value = false;static void execute(const typename std::decay<T>::type & t){ std::cout<<"no function to call"<<std::endl;}};template<class T>class A <T, typename std::enable_if< hasOperatorParentheses<T>::value >::type > {public:static const bool value = true;static void execute(const typename std::decay<T>::type & t){ const_cast<typename std::decay<T>::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。没有其他特别的用途,可以不使用。



0 0
原创粉丝点击