使用SFINAE检查成员函数并调用它

时间:2017-12-13 23:39:26

标签: c++ c++17 sfinae

我想了解SFINAE的工作原理。

我的需求:

我有一组类型,可以提供或不提供名为activate的成员函数。问题是如果给定类型确实存在activate,它可以接受任何参数。我想编写一个函数,该函数将转发到类型activate,如果它存在,否则只是return true

我试过了:

#include <iostream>
#include <utility>
#include <functional>

struct A
{
    bool activate()
    {   
        std::clog << "A::activate() called" << std::endl;
        return true;
    }   

    bool activate(const char*)
    {   
        std::clog << "A::activate(const char*) called" << std::endl;
        return true;
    }   
};

struct B
{
    // NOTHING
};

template<class S, class... ARGS>
auto activate(S& s, ARGS&&... p_args) -> typename std::invoke_result<decltype(&S::activate)(S, ARGS...)>::type
{
    return s.activate(std::forward<ARGS>(p_args)...);
}

bool activate(...)
{
    return true;
}


int main(int argc, char* argv[])
{
    A a;
    B b;

    activate(a);
    activate(a, "Hello");
    activate(b);

    return 0;
}

但是没有任何印刷品。为什么呢?

1 个答案:

答案 0 :(得分:3)

你的问题在这里:

template<class S, class... ARGS>
auto activate(S& s, ARGS&&... p_args)
    -> typename std::invoke_result<decltype(&S::activate)(S, ARGS...)>::type
//                                          ^^^^^^^^^^^^

如果activate是重载的成员函数,就像A一样,您无法通过decltype获取其地址。其次,invoke_result的使用不正确 - 它没有使用result_of的{​​{1}}语法,你只需要F(Args...)。它更简单。

你想要的只是自己直接调用它:

invoke_result<F, Args...>

这一方面解决了重载名称以及如何使用template<class S, class... ARGS> auto activate(S& s, ARGS&&... p_args) -> decltype(s.activate(std::forward<ARGS>(p_args)...)) 的问题。