Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 Change `auto` Lambda to a different Lambda?

Say I have the following variable containing a lambda:

auto a = [] { return true; };

And I want a to return false later on. Could I do something along the lines of this?

a = [] { return false; };

This syntax gives me the following errors:

binary '=' : no operator found which takes a right-hand operand of type 
'main::<lambda_a7185966f92d197a64e4878ceff8af4a>' (or there is no acceptable conversion)

IntelliSense: no operator "=" matches these operands
        operand types are: lambda []bool ()->bool = lambda []bool ()->bool

Is there any way to achieve something like this? I would like to change the auto variable to a different lambda. I'm relitively a beginner so I may be missing some knowledge about auto or lambdas. Thanks.

like image 544
Archie Gertsman Avatar asked Jul 27 '16 19:07

Archie Gertsman


People also ask

What is the correct syntax for lambda expression in C++11?

Lambdas can both capture variables and accept input parameters. A parameter list (lambda declarator in the Standard syntax) is optional and in most aspects resembles the parameter list for a function. auto y = [] (int first, int second) { return first + second; };

What is auto lambda expression?

Immediately invoked lambda expression is a lambda expression which is immediately invoked as soon as it is defined. For example, #include<iostream> using namespace std; int main(){ int num1 = 1; int num2 = 2; // invoked as soon as it is defined auto sum = [] (int a, int b) { return a + b; } (num1, num2);

Are C++ lambdas closures?

In C++, lambda expression constructs a closure, an unnamed function object capable of capturing variables in scope.

What does [&] mean in C++?

It's a lambda capture list and has been defined in C++ from the C++11 standard. [&] It means that you're wanting to access every variable by reference currently in scope within the lambda function.


5 Answers

Every lambda expression creates a new unique type, so the type of your first lambda is different from the type of your second (example). Additionally the copy-assignment operator of a lambda is defined as deleted (example) so you're doubly-unable to do this. For a similar effect, you can have a be a std::function object though it'll cost you some performance

std::function<bool()> a = [] { return true; };
a = [] { return false; };
like image 192
Ryan Haining Avatar answered Oct 05 '22 05:10

Ryan Haining


A Lambda may be converted to a function pointer using the unary + operator like so:

+[]{return true;}

so long as the capture group is empty and it doesn't have auto arguments.1

If you do this, you may assign different lambdas to the same variable as long as the lambdas all have the same signature.

In your case,

auto a = +[]{return true;};
a = +[]{return false;};

Live example on Coliru

would both compile and act as you expect.2 You may use the function pointers in the same way you would expect to use a lambda, since both will act as functors.


1. In C++14, you can declare lambdas with auto as the argument type, like [](auto t){}. These are generic lambdas, and have a templated operator(). Since a function pointer can't represent a templated function, the + trick won't work with generic lambdas.

2. Technically, you don't need the second + operator on the assignment. The lambda would convert to the function pointer type on assignment. I like the consistency, though.

like image 26
jaggedSpire Avatar answered Oct 05 '22 05:10

jaggedSpire


Each lambda has a different type so you cannot change it. You could use a std::function to hold an arbitrary callable object, that can be changed at will.

std::function <bool ()> a = [] { return true; };
a = [] { return false; };
like image 22
nate Avatar answered Oct 05 '22 04:10

nate


We may use retrospective call to convert lambda to std::function:

template<typename T>
struct memfun_type
{
  using type = void;
};

template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
  using type = std::function<Ret(Args...)>;
};

template<typename F>
typename memfun_type<decltype(&F::operator())>::type
FFL(F const &func)
{ // Function from lambda !
  return func;
}

After that we will be able to do (since 'a' is std::function type now ):

auto a = FFL([] { return false; });
a = FFL([] { return true; });
like image 36
Alex Melnikov Avatar answered Oct 05 '22 05:10

Alex Melnikov


Since C++17 you can have the std::function template parameter deduced thanks to Class template argument deduction. It even works with capturing lambdas:

int a = 24;

std::function f = [&a] (int p) { return p + a; };
f               = [&a] (int p) { return p - a; };
f               = []   (int p) { return p; };

This comes in handy with more complex signatures and even more with deduced return types.

like image 28
bolov Avatar answered Oct 05 '22 06:10

bolov