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; };
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
.
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; }};
A lambda in C++ is an instance of local class implementing functor contract. I mean, operator() etc. And these classes are unrelated and have different types.
Your code is equivalent to
struct l1 {
bool operator () const {
return true;
}
};
struct l2 {
private int number_:
l2(int number): number_(number){}
bool operator () const {
return number_ == 123;
}
};
int number = ???
auto l3 = condition ? l1 : l2(number);