I want to define a function that takes (besides its usual input arguments) a lambda function. And I want to restrict that function as far as possible (its own input- and return types).
int myfunc( const int a, LAMBDA_TYPE (int, int) -> int mylamda )
{
return mylambda( a, a ) * 2;
}
Such that I can call the function as follows:
int input = 5;
myfunc( input, [](int a, int b) { return a*b; } );
What is the correct way to define myfunc
?
And is there a way to define a default lambda? Like this:
int myfunc( const int a, LAMBDA_TYPE = [](int a, int b) { return a*b; });
If you take a std::function<int(int,int)>
it will have overhead, but it will do what you want. It will even overload correctly in C++14.
If you do not want type erasure and allocation overhead of std::function
you can do this:
template<
class F,
class R=std::result_of_t<F&(int,int)>,
class=std::enable_if_t<std::is_same<int,R>{}>
>
int myfunc( const int a, F&& f )
or check convertability to int
instead of sameness. This is the sfinae solution. 1
This will overload properly. I used some C++14 features for brevity. Replace blah_t<?>
with typename blah<?>::type
in C++11.
Another option is to static_assert
a similar clause. This generates the best error messages.
Finally you can just use it: the code will fail to compile if it cannot be used the way you use it.
In C++1z concepts there will be easier/less code salad ways to do the sfinae solution.
1 On some compilers std::result_of
fails to play nice with sfinae. On those, replace it with decltype(std::declval<F&>()(1,1))
. Unless your compiler does not support C++11 (like msvc 2013 and 2015) this will work. (luckily 2013/3015 has a nice result_of
).
There are two alternatives, the type-erasing std::function<signature>
forces a particular signature which goes along the lines of your question, but it imposes some additional cost (mainly it cannot be inlined in general). The alternative is to use a template an leave the last argument as a generic object. This approach can be better from a performance point of view, but you are leaving the syntax checking to the compiler (which I don't see as a problem). One of the comments mentions passing a lambda as a function pointer , but that will only work for lambdas that have no capture.
I would personally go for the second option:
template <typename Fn>
int myFunc(const int a, Fn&& f) {
return f(a, a) * 2;
}
Note that while this does not explicitly force a particular signature, the compiler will enforce that f
is callable with two int
and yields something that can be multiplied by 2 and converted to int
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.