Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing capturing lambda in ternary operator

I wanted to create a lambda in the following way:

auto l1 = condition ?           [](){ return true; } :           [number](){ return number == 123; }; 

However, I got error:

operands to ?: have different types ‘main()::<lambda()>’ and ‘main()::<lambda()>’ 

Obviously, the types seem to be the same. I thought, that capturing number in only one of lambdas might be a problem, but I get the same error for these:

//check if capturing number in both lambdas would help auto l2 = condition ?           [number](){ return true; } :           [number](){ return number == 123; }; //maybe the first lambda capture was optimised out? let's make sure: auto l3 = condition ?           [number](){ return number != 123; } :           [number](){ return number == 123; }; 

I'm aware I can do it other way (below), but I'm wondering what is the cause of this behavior. It was compiled with GCC6.3.1, C++14 enabled.

//compiles       auto l4 = condition ?           [](const int){ return true; } :           [](const int number){ return number == 123; }; 
like image 376
knopers8 Avatar asked Jan 23 '18 08:01

knopers8


People also ask

Can we use ternary operator in lambda expression?

It is also called a Ternary operator because it has three operands such as boolean condition, first expression, and second expression. We can also write a conditional expression in lambda expression in the below program.

How do you declare lambda in C++?

Creating a Lambda Expression in C++auto greet = []() { // lambda function body }; Here, [] is called the lambda introducer which denotes the start of the lambda expression. () is called the parameter list which is similar to the () operator of a normal function.

What does [=] mean in lambda function?

The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.

What does it mean to lambda capture this?

The lambda is capturing an outside variable. A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.


2 Answers

Every lambda expression has unique type (i.e. the closure type, which is a unique unnamed non-union non-aggregate class type), even with the same signature and function body; the compiler just can't deduce the common type of ternary conditional operator for the variable declared by auto, the two closure types are irrelevant at all.

You can use std::function instead. e.g.

std::function<bool()> l1; if (condition)      l1 = [](){ return true; }; else      l1 = [number](){ return number == 123; }; 

For l4, note that the lambda-expression with empty capture list could be converted to the corresponding function pointer implicitly. In this case both of them could be converted to the same function pointer type (i.e. bool(*)(int)), which then could be deduced as the common type of ternary conditional operator and the type of l4.

like image 187
songyuanyao Avatar answered Sep 21 '22 13:09

songyuanyao


If you really want to use the conditional operator you can do it like this:

auto l1 = condition           ? std::function<bool()>{[](){ return true; }}           : std::function<bool()>{[number](){ return number == 123; }}; 

In C++17 this can be simplified thanks to Class template argument deduction:

auto l1 = condition           ? std::function{[](){ return true; }}           : std::function{[number](){ return number == 123; }}; 
like image 38
bolov Avatar answered Sep 22 '22 13:09

bolov