Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 type inference with lambda and std::function

I have the following snippet of code, that although entirely trivial, illustrates a pattern I am trying to use in more general code.

template<typename InT, typename ResT>
ResT unary_apply( InT val, std::function<ResT(InT)> fn )
{
    return fn(val);
}

I would like to be able to call unary_apply with function pointers, functors, lambdas etc: hence the use of std::function to abstract that all away.

When I try to use the above in the following way, C++ (g++ 4.7) is unable to perform the relevant type inference:

double blah = unary_apply( 2, []( int v ) { return 3.0 * v; } );

Failing with

src/fun.cpp:147:75: error: no matching function for call to ‘unary_apply(int, test()::<lambda(int)>)’
src/fun.cpp:147:75: note: candidate is:
src/fun.cpp:137:6: note: template<class InT, class ResT> ResT unary_apply(InT, std::function<ResT(InT)>)
src/fun.cpp:137:6: note:   template argument deduction/substitution failed:
src/fun.cpp:147:75: note:   ‘test()::<lambda(int)>’ is not derived from ‘std::function<ResT(double)>’

And I find that I have to explicitly specify the template parameters (in practice I believe it is just the return type that is not inferable):

double blah = unary_apply<int, double>( 2, []( int v ) { return 3.0 * v; } );

I am not that familiar with the type inference rules in C++11, but the above behaviour does seem reasonable (I can see that inferring via the internal mechanics of std::function is probably rather a big ask). My question is: is it possible to re-write the unary_applyfunction above to keep the same flexibility (in terms of the types of functions/functors etc that can be passed as a second parameter) whilst also giving more of a clue to type inference so I do not have to explicitly supply the template parameters at the point of call?

like image 485
Alex Wilson Avatar asked Jul 05 '12 12:07

Alex Wilson


People also ask

What is a lambda function in C++11?

Lambda Functions in C++11 - the Definitive Guide. A lambda function is a function that you can write inline in your source code (usually to pass in to another function, similar to the idea of a functor or function pointer ). With lambda, creating quick functions has become much easier, and this means that not only can you start using lambda...

Can a lambda function be assigned to a function pointer?

Under the final C++11 spec, if you have a lambda with an empty capture specification, then it can be treated like a regular function and assigned to a function pointer. Here's an example of using a function pointer with a capture-less lambda:

What is the difference between lambda function and capture by reference?

When you capture by reference, the lambda function is capable of modifying the local variable outside the lambda function--it is, after all, a reference. But this also means that if you return a lamba function from a function, you shouldn't use capture-by-reference because the reference will not be valid after the function returns.

How to use lambda function for multi-threading in C++11?

Lambda function was briefly introduced in C++11 Thread 1. Creating Threads. In this section, we'll see the usefulness of lambda function for multi-threading. Let's start from where we left: We're going to create 5 more threads, and put those into std::vector container. For the join (), we'll use for_each (): Output should look like this:


1 Answers

Going bit more duck-typey should work:

template <typename T, typename F>
auto unary_apply(T&& val, F&& func) -> decltype(func(val)) {
    return func(std::forward<T>(val));
}
like image 152
Cat Plus Plus Avatar answered Oct 03 '22 07:10

Cat Plus Plus