How to Use Lambda Auto Parameters in C++11

How to use lambda auto parameters in C++11

C++11 doesn't support generic lambdas. That's what auto in the lambda's parameter list actually stands for: a generic parameter, comparable to parameters in a function template. (Note that the const isn't the problem here.)

Note: C++14 does support lambdas with auto, const auto, etc. You can read about it here.

You have basically two options:

  1. Type out the correct type instead of auto. Here it is the element type of X, which is pair<double, vector<int>>. If you find this unreadable, a typedef can help.

    std::stable_sort(X.rbegin(), X.rend(),
    [](const pair<double, vector<int>> & lhs,
    const pair<double, vector<int>> & rhs)
    { return lhs.first < rhs.first; });
  2. Replace the lambda with a functor which has a call operator template. That's how generic lambdas are basically implemented behind the scene. The lambda is very generic, so consider putting it in some global utility header. (However do not using namespace std; but type out std:: in case you put it in a header.)

    struct CompareFirst {
    template <class Fst, class Snd>
    bool operator()(const pair<Fst,Snd>& l, const pair<Fst,Snd>& r) const {
    return l.first < r.first;
    }
    };
    std::stable_sort(X.rbegin(), X.rend(), CompareFirst());

C++11: how to use lambda as type parameter, where it requires a functor type like std::less/std::greater?

There are multiple ways:

  1. Let the compiler deduce the type of lamabda by using decltype(lambda). But one thing you need to keep in mind: Prior to C++20, lambda type does not have a default constructor. As of C++20, ONLY stateless lambda (lambda without captures) has a default constructor, while stateful lambda (i.e., lambda with captures) has no default constructor (This is clearly documented on cppreference.com). Why does the default constructor matter here? The answer is that if a default constructor exists, you don't have to pass a compare function (cmp) to the priority_queue constructor as long as you specified the lambda type as the template argument. Since the default constructor exists only for stateless lambda starting from C++20, you'd better explicitly pass a cmp argument to the constructor:
auto cmp = [](int x, int y){return x>y;}; 
priority_queue<int, vector<int>, decltype(cmp)> q(cmp);

  1. Use the <functional> header to explicitly specify the lambda type:
#include <functional>
...
priority_queue<int, vector<int>, function<bool(int, int)>> q(cmp);

  1. Use a function-obejct class. In this case, you only need to specify the function-object class as a template type argument, and you don't need to pass the cmp argument to the constructor, because your own defined function-object class has a default (synthesized) constructor.
struct Cmp {
bool operator()(int x, int y) {return x > y;}
};
priority_queue<int, vector<int>, Cmp> q;

  1. Use the library-defined function objects whenever possible.
priority_queue<int, vector<int>, std::greater<int>> q;

Access auto parameter's type within lambda

The type of value is an lvalue-reference, you can't get the member type from it and have to remove the reference part, e.g

typename std::decay_t<decltype(value)>::value_type v;

PS: You also need to add typename in advance (as @Vlad answered) for the dependent type name. See Where and why do I have to put the “template” and “typename” keywords?.

LIVE

How to make C++11 functions taking function<> parameters accept lambdas automatically

Finally figured out a generic wrapper function make_function (in current c++11) for converting any lambda to its corresponding std::function object with type deduction. Now instead of using ctor:

map(function<int (int)>( [](int x) -> int { return x;} ), {1,2,3});

which requires giving the same type information twice, the following succinct form works

map(make_function([](int x) -> int { return x;}),a); //now OK

Code is below:

 #include <vector>
#include <functional>
using namespace std;

template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
typedef function<ReturnType (Args...)> f_type;
};

template <typename L>
typename function_traits<L>::f_type make_function(L l){
return (typename function_traits<L>::f_type)(l);
}

template <typename A,typename B>
vector<B> map(std::function<B (A)> f, vector<A> arr) {
vector<B> res;
for (int i=0;i<arr.size();i++) res.push_back(f(arr[i]));
return res;
}

int main () {
vector<int> a = {1,2,3};
map(make_function([](int x) -> int { return x;}),a); //now OK
return 0;
}

--original answer--

To answer my own question after a couple of weeks' search (and getting chastised for using std::function<> as parameters), probably the best way I can find to have function<>-typed parameters accept lambda's (in c++11) is simply via explicit cast:

map((function<int (int)>) ([](int x) -> int { return x;} ), {1,2,3});

Or using ctor:

map(function<int (int)>( [](int x) -> int { return x;} ), {1,2,3});

For comparison, if you have a function taking std::string (e.g. void ff(string s) {...}), it can take const char* automatically. (ff("Hi") would work). The automatic conversion from lambda to std::function<> does not similarly work in c++11 (, which is unfortunate, IMO).

Hopefully, things will improve in c++14/1y when lambdas can be properly typed or better type-deduced.

C++11 lambda function - how to pass parameter

Show lambda with parameters are used? How to pass parameters to them?

It works exactly like with any other type of callable object:

#include <iostream>

int main()
{
auto l = [] (int i) { std::cout << "The answer is " << i; };
l(42);
}

Also notice, that you do not need to store a lambda in a variable in order to invoke it. The following is an alternative way to rewrite the above program:

#include <iostream>

int main()
{
[] (int i) { std::cout << "The answer is " << i; } (42);
// ^^^^
// Invoked immediately!
}

The type of a lambda function (the so-called "lambda closure") is defined by the compiler, and is a functor with a call operator whose signature is the one you specify when defining the lambda. Therefore, you call a lambda exactly as you would call a functor (i.e. exactly as you would call a function - or any callable object).

Thus, if you want to assign a lambda to an object, the best practice is to let the compiler deduce its type by using auto. If you do not want or cannot use auto, then you may:

  1. Use function pointers for non-capturing lambdas (capturing lambdas are not convertible to function pointers). In the above case, thus, the following will also work:

    #include <iostream>

    int main()
    {
    void (*f)(int) = [] (int i) { std::cout << "The answer is " << i; };
    f(42);
    }
  2. Use std::function (this is always possible, even if the lambda is capturing):

    #include <iostream>
    #include <functional>

    int main()
    {
    std::function<void(int)> f = [] (int i)
    { std::cout << "The answer is " << i; };
    f(42);
    }

Auto parameter type in lambda causes Use 'template' keyword to treat... error

Now that you have a template type (in the form of auto) instead of a concrete type TestClass, the get function is dependent, and therefore you need to qualify it with the template keyword:

tc.template get<int>();

Use a lambda as a parameter for a C++ function

You have 2 ways: make your function template:

template <typename F>
void myFunction(F&& lambda)
{
//some things
}

or erase type (with std::function for example):

void
myFunction(const std::function<void()/*type of your lamdba::operator()*/>& f)
{
//some things
}

How to constrain an auto lambda parameter to a pointer to member function?

You can declare it as:

auto l = [](auto S::*pmf)

It does tie the pointer to a S type, but it makes sense because it is that way you will use it.

Parameter list in Lambda

Lambda creation

I think I had the same confusion when I first saw lambdas.

So let's see what this expression means:

[](auto x, auto y) {return(y < x); }

This just creates the lambda object. It does not call the labda. Think of it as a class definition + object creation.

Your questions

Let's consider the declaration of sort:

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

and your call to it

sort(ivec.begin(), ivec.end(), [](auto x, auto y) { return(y < x); });

when the above line of code is being executed?

I'll interpret this as "when is the body of the lambda executed?"

Whenever sort calls it. What you need to understand: sort receives a parameter named comp that is callable. This parameter can be of type: pointer to function or a callable type (i.e. a type with operator() defined). A lambda is a special case of a callable type. When you call sort you just pass this object to the sort function. Now sort has an object (comp) that it can call whenever it wants/needs.

what is being passed in the parameter list as parameter?

Whatever sort passes as arguments when it calls comp. It the case of std::sort it will call it with pairs of elements from the range with the purpose of determining if those two elements are already sorted between them or not.

Example

The easiest is to just see it in action. For this lets consider the simplest sorting algorithm: a dumb bubble sort:

template< class RandomIt, class Compare >
void bubble_sort( RandomIt first, RandomIt last, Compare comp )
{
for (auto left = first; left != last; ++left)
{
for (auto right = std::next(left); right != last; ++right)
{
if (!comp(*left, *right))
{
std::swap(*left, *right);
}
}
}
}

the algorithm is for exposition only

As you can see bubble_sort makes calls to comp by passing arguments. Like std::sort the arguments passed are pairs of elements from the [first, last) range.



Related Topics



Leave a reply



Submit