问题
I have a bunch of functions which I want to use as functors (that is, use types instead of pass pointers to the functions, or any other kind of data).
Is there an elegant/idiomatic/standard way of doing this with the standard library, or the standard library + Boost? Perhaps using bind()
somehow?
Or should I go with something simplistic (well, kind of simplistic) such as:
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)...);
}
};
Notes:
- C++11 solutions are preferred, but if you have something requiring even C++17, that's also interesting.
- My "solution" might not work, I think, for overloaded functions.
回答1:
First, a concrete example for a fixed type.
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)... ) ); }
};
now foo_t
is an object that invokes the overloads of foo
via perfect forwarding.
To make it generic:
#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)... ) ) \
}
so we can do
using foo_t = OVERLOAD_SET_TYPE(foo);
live example.
You cannot manipulate overload sets of a function as an object; the only way to do it is textually. Hence the macro.
This has all of the usual imperfections of perfect forwarding. There is no way to generically avoid those imperfections.
回答2:
If the function is not overloaded, you can do this in 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);
}
If the function is overloaded, there's no way to pass its overload set as an argument to another function or a template. You're forced to manually write a wrapper lambda on the spot. Example:
void foo(int) { }
void foo(char) { }
// ...
bar([](auto x){ return foo(x); });
N3617 aimed to solve this issue by introducing a "lift" operator.
P0119 by A. Sutton solves the problem in a different way by allowing overload sets to basically generate the "wrapper lambda" for you when passed as arguments.
Until any of those proposal is accepted you can use a beautiful C++14 macro instead:
#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)...); \
}
来源:https://stackoverflow.com/questions/43504566/how-do-i-make-a-functor-out-of-an-arbitrary-function