如果要将可调用对象转换为std::function
不指定签名者的签名std::function
,这正是C++17 的推导指南std::function是给。我们只需要为 C++11 实现一个版本。请注意,这仅适用于具有非重载的可调用对象operator()
;否则,没有办法做到这一点。
#include <functional>
#include <utility> // std::declval
// Using these functions just for the return types, so they don't need an implementation.
// Support function pointers
template <typename R, typename... ArgTypes>
auto deduce_std_function(R(*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
// Support callables (note the _impl on the name).
// Many overloads of this to support different const qualifiers and
// ref qualifiers. Technically should also support volatile, but that
// doubles the number of overloads and isn't needed for this illustration.
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) &) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const&) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) &&) -> std::function<R(ArgTypes...)>;
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...) const&&) -> std::function<R(ArgTypes...)>;
// To deduce the function type for a callable, get its operator() and pass that to
// the _impl functions above.
template <typename Function>
auto deduce_std_function(Function)
-> decltype(deduce_std_function_impl(&Function::operator()));
template <typename Function>
using deduce_std_function_t = decltype(deduce_std_function(std::declval<Function>()));
template <typename F>
auto to_std_function(F&& fn) -> deduce_std_function_t<F> {
return deduce_std_function_t<F>(std::forward<F>(fn));
}
Demo
更详细的解释
我们需要推断出函数类型std::function<...>
。所以我们需要实施某种deduce_std_function
计算出函数类型。有多种选择可以实现此目的:
- Make a
function_traits
type 为我们计算出函数类型(类似于您的lambda_traits
).
- 实施
deduce_std_function
作为重载集,其中重载的返回类型是推导类型。
我选择后者是因为它模仿演绎指南。前者也可以,但我认为这种方法可能更容易(函数样板比结构样板小)。
简单的情况
查看文档std::function
的推演指南,有一个简单的:
template<class R, class... ArgTypes>
function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;
这可以很容易地翻译成:
template <typename R, typename... ArgTypes>
auto deduce_std_function(R(*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
基本上,给定任何函数指针R(*)(ArgTypes...)
,我们想要的类型是std::function<R(ArgTypes...)>
.
更棘手的情况
文档将第二种情况描述为:
此重载仅参与重载决策,如果&F::operator()
当被视为未评估的操作数时是格式良好的
和decltype(&F::operator())
是这样的形式R(G::*)(A...)
(可选
cv 限定,可选 noexcept,可选左值引用
合格)对于某些类类型 G。推导出的类型是std::function<R(A...)>
.
那是一口。然而,这里的关键思想是:
- "
decltype(&F::operator())
是这样的形式R(G::*)(A...)
"
- “推导出来的类型是
std::function<R(A...)>
"
这意味着我们需要获取指向成员函数的指针operator()
并使用该成员函数指针的签名作为std::function
.
这就是它的来源:
template <typename Function>
auto deduce_std_function(Function)
-> decltype(deduce_std_function_impl(&Function::operator()));
我们委托给deduce_std_function_impl
因为我们需要推导出成员函数指针的签名&Function::operator()
.
该 impl 函数的有趣重载是:
template <typename F, typename R, typename... ArgTypes>
auto deduce_std_function_impl(R(F::*)(ArgTypes...)) -> std::function<R(ArgTypes...)>;
简而言之,我们正在获取签名(R ... (ArgTypes...)
位)的成员函数指针并将其用于std::function
。语法的其余部分((F::*)
bit) 只是指向成员函数的指针的语法。R(F::*)(ArgTypes...)
是类的成员函数指针的类型F
与签名R(ArgTypes...)
并且没有 const、易失性或引用限定符。
可是等等!我们希望支持 const 和引用限定符(您可能也希望添加对 volatile 的支持)。所以我们需要复制deduce_std_function_impl
上面,每个预选赛一次:
Signature |
Class Declaration |
R(F::*)(ArgTypes...) |
void operator()(); |
R(F::*)(ArgTypes...) const |
void operator()() const; |
R(F::*)(ArgTypes...) & |
void operator()() &; |
R(F::*)(ArgTypes...) const& |
void operator()() const&; |
R(F::*)(ArgTypes...) && |
void operator()() &&; |
R(F::*)(ArgTypes...) const&& |
void operator()() const&&; |