如何从任意函数中创建仿函数?
How do I make a functor out of an arbitrary function?
我有一堆函数想用作仿函数(也就是说,使用类型而不是将指针传递给函数或任何其他类型的数据)。
是否有 elegant/idiomatic/standard 使用标准库或标准库 + Boost 执行此操作的方法?也许以某种方式使用 bind()
?
或者我应该使用一些简单的东西(好吧,有点简单),例如:
template<typename Function, Function& F, typename... Parameters>
struct functor {
using function_type = Function;
using parameters_as_tuple_type = std::tuple<Parameters...>;
auto operator() (Parameters&&... params) ->
decltype(F(std::forward<Parameters>(params)...))
{
return F(std::forward<Parameters>(params)...);
}
};
备注:
- C++11 解决方案是首选,但如果您有一些甚至需要 C++17 的东西,那也很有趣。
- 我认为我的 "solution" 对于重载函数可能不起作用。
如果函数没有被重载,你可以在C++17中这样做:
template <auto F>
auto to_function_object()
{
return [](auto&&... xs) -> decltype(auto)
{
return F(std::forward<decltype(xs)>(xs)...);
};
}
void a(int) { }
int main()
{
auto af = to_function_object<a>();
af(1);
}
如果函数被重载,则无法将其 重载集 作为参数传递给另一个函数或模板。您被迫当场手动编写包装器 lambda。示例:
void foo(int) { }
void foo(char) { }
// ...
bar([](auto x){ return foo(x); });
N3617 旨在通过引入 "lift" 运算符.
来解决此问题
A. Sutton 的 P0119 通过允许重载集在作为参数传递时基本上为您生成 "wrapper lambda" 以不同的方式解决了这个问题。
在接受任何这些建议之前,您可以使用 漂亮 C++14 宏代替:
#define LIFT(f) \
[](auto&&... xs) noexcept(noexcept(f(std::forward<decltype(xs)>(xs)...))) \
-> decltype(f(std::forward<decltype(xs)>(xs)...)) \
{ \
return f(std::forward<decltype(xs)>(xs)...); \
}
首先,固定类型的具体示例。
int foo( int );
void foo( double );
struct foo_t {
template<class...Args>
auto operator()(Args&&...args)const
->decltype( foo( std::declval<Args>()... ) )
{ return ( foo( std::forward<Args>(args)... ) ); }
};
现在foo_t
是一个通过完美转发调用foo
重载的对象。
使其通用:
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
#define OVERLOAD_SET_TYPE(...) \
struct { \
template<class...Args> \
auto operator()(Args&&...args)const \
RETURNS( __VA_ARGS__( std::forward<Args>(args)... ) ) \
}
所以我们可以做到
using foo_t = OVERLOAD_SET_TYPE(foo);
您不能将函数的重载集作为对象进行操作;唯一的方法是通过文字。因此宏。
这具有完美转发的所有常见缺陷。一般无法避免这些缺陷。
我有一堆函数想用作仿函数(也就是说,使用类型而不是将指针传递给函数或任何其他类型的数据)。
是否有 elegant/idiomatic/standard 使用标准库或标准库 + Boost 执行此操作的方法?也许以某种方式使用 bind()
?
或者我应该使用一些简单的东西(好吧,有点简单),例如:
template<typename Function, Function& F, typename... Parameters>
struct functor {
using function_type = Function;
using parameters_as_tuple_type = std::tuple<Parameters...>;
auto operator() (Parameters&&... params) ->
decltype(F(std::forward<Parameters>(params)...))
{
return F(std::forward<Parameters>(params)...);
}
};
备注:
- C++11 解决方案是首选,但如果您有一些甚至需要 C++17 的东西,那也很有趣。
- 我认为我的 "solution" 对于重载函数可能不起作用。
如果函数没有被重载,你可以在C++17中这样做:
template <auto F>
auto to_function_object()
{
return [](auto&&... xs) -> decltype(auto)
{
return F(std::forward<decltype(xs)>(xs)...);
};
}
void a(int) { }
int main()
{
auto af = to_function_object<a>();
af(1);
}
如果函数被重载,则无法将其 重载集 作为参数传递给另一个函数或模板。您被迫当场手动编写包装器 lambda。示例:
void foo(int) { }
void foo(char) { }
// ...
bar([](auto x){ return foo(x); });
N3617 旨在通过引入 "lift" 运算符.
来解决此问题 A. Sutton 的P0119 通过允许重载集在作为参数传递时基本上为您生成 "wrapper lambda" 以不同的方式解决了这个问题。
在接受任何这些建议之前,您可以使用 漂亮 C++14 宏代替:
#define LIFT(f) \
[](auto&&... xs) noexcept(noexcept(f(std::forward<decltype(xs)>(xs)...))) \
-> decltype(f(std::forward<decltype(xs)>(xs)...)) \
{ \
return f(std::forward<decltype(xs)>(xs)...); \
}
首先,固定类型的具体示例。
int foo( int );
void foo( double );
struct foo_t {
template<class...Args>
auto operator()(Args&&...args)const
->decltype( foo( std::declval<Args>()... ) )
{ return ( foo( std::forward<Args>(args)... ) ); }
};
现在foo_t
是一个通过完美转发调用foo
重载的对象。
使其通用:
#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }
#define OVERLOAD_SET_TYPE(...) \
struct { \
template<class...Args> \
auto operator()(Args&&...args)const \
RETURNS( __VA_ARGS__( std::forward<Args>(args)... ) ) \
}
所以我们可以做到
using foo_t = OVERLOAD_SET_TYPE(foo);
您不能将函数的重载集作为对象进行操作;唯一的方法是通过文字。因此宏。
这具有完美转发的所有常见缺陷。一般无法避免这些缺陷。