Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write a function that accepts a lambda expression as argument

Tags:

c++

c++11

lambda

I have a method like this

template<typename T, typename U> map<T,U> mapMapValues(map<T,U> old, T (f)(T,U)) {     map<T,U> new;     for(auto it = old.begin(); it != old.end(); ++it)     {         new[it->first] = f(it->first,it->second);     }     return new;  } 

and the idea is that you'd call it like this

BOOST_AUTO_TEST_CASE(MapMapValues_basic) {     map<int,int> test;     test[1] = 1;     map<int,int> transformedMap = VlcFunctional::mapMapValues(test,          [&](int key, int value) -> int         {             return key + 1;          }     ); } 

However I get the error: no instance of function template "VlcFunctional::mapMapValues" matches the argument list argument types are: (std::map, std::allocator>>, __lambda1)

Any idea what I'm doing wrong? Visual Studio 2008 and Intel C++ compiler 11.1

like image 726
Jamie Cook Avatar asked Jul 08 '10 12:07

Jamie Cook


People also ask

How do you use lambda as an argument in python?

Syntax. Simply put, a lambda function is just like any normal python function, except that it has no name when defining it, and it is contained in one line of code. A lambda function evaluates an expression for a given argument. You give the function a value (argument) and then provide the operation (expression).

How do you define a lambda function with two arguments?

Just like a normal function, a Lambda function can have multiple arguments with one expression. In Python, lambda expressions (or lambda forms) are utilized to construct anonymous functions. To do so, you will use the lambda keyword (just as you use def to define normal functions).

What is a lambda argument?

In Python, a lambda function is a single-line function declared with no name, which can have any number of arguments, but it can only have one expression. Such a function is capable of behaving similarly to a regular function declared using the Python's def keyword.

How do you accept a lambda function as a parameter in Java?

If you are passing an instance of a class as a parameter, you must specify the class name or the object class as a parameter to hold the object. In Java, there is no type for lambda expression. Instead, it would help if you used an interface, i.e., a functional interface, to accept the parameter.


2 Answers

Your function is expecting a function pointer, not a lambda.

In C++, there are, in general, 3 types of "callable objects".

  1. Function pointers.
  2. Function objects.
  3. Lambda functions.

If you want to be able to use all of these in your function interface, then you could use std::function:

template<typename T, typename U>  map<T,U> mapMapValues(map<T,U> old, std::function<T(T, U)> f) {     ... } 

This will allow the function to be called using any of the three types of callable objects above. However, the price for this convenience is a small amount of overhead on invokations on the function (usually a null pointer check, then a call through a function pointer). This means that the function is almost certainly not inlined (except maybe with advanced WPO/LTO).

Alternatively, you could add an additional template parameter to take an arbitrary type for the second parameter. This will be more efficient, but you lose type-safety on the function used, and could lead to more code bloat.

template<typename T, typename U, typename F>  map<T,U> mapMapValues(map<T,U> old, F f)  
like image 85
Peter Alexander Avatar answered Sep 24 '22 17:09

Peter Alexander


Your parameter type declaration T (f)(T,U) is of type 'free function taking a T and a U and returning a T'. You can't pass it a lambda, a function object, or anything except an actual function with that signature.

You could solve this by changing the type of the parameter to std::function<T(T,U)> like this:

template<typename T, typename U>  map<T,U> mapMapValues(map<T,U> old, std::function<T(T,U)>) { } 

Alternately, you could declare the function type as a template argument like this:

template<typename T, typename U, typename Fn>  map<T,U> mapMapValues(map<T,U> old, Fn fn) {   fn(...); } 
like image 20
JoeG Avatar answered Sep 24 '22 17:09

JoeG