使用 SFINAE 检查成员函数并调用它
Using SFINAE to check for member function and call it
我想了解 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;
}
但是什么也没有打印出来。为什么?
您的问题在这里:
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
的错误使用——它没有使用 F(Args...)
的 result_of
语法,你只是使用 invoke_result<F, Args...>
。更简单。
你想要的是自己直接调用它:
template<class S, class... ARGS>
auto activate(S& s, ARGS&&... p_args)
-> decltype(s.activate(std::forward<ARGS>(p_args)...))
这回避了重载名称的问题,以及如何使用 invoke_result
。
我想了解 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;
}
但是什么也没有打印出来。为什么?
您的问题在这里:
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
的错误使用——它没有使用 F(Args...)
的 result_of
语法,你只是使用 invoke_result<F, Args...>
。更简单。
你想要的是自己直接调用它:
template<class S, class... ARGS>
auto activate(S& s, ARGS&&... p_args)
-> decltype(s.activate(std::forward<ARGS>(p_args)...))
这回避了重载名称的问题,以及如何使用 invoke_result
。