I have the following code:
int main() {
auto f = [] {
if (1) return [] { return 1; };
else return [] { return 2; };
};
return f()();
}
which raises the following compiler error using GCC 5.2.1:
error: inconsistent types ‘main()::<lambda()>::<lambda()>’ and
‘main()::<lambda()>::<lambda()>’ deduced for lambda
return type else return [] { return 2; };
Now obviously those two types look to be the same, so I'm not sure if this is GCC with a misleading error message or if it's actually a bug. According to my knowledge this should compile; the lambda return type should be deduced to be std::function<int()>
. Interestingly, if I pre-declare the lambda return and return the same variable twice, it works.
Can anyone shed some light as to what is happening? I found similar looking questions, many attributed to GCC bugs, but this looks different.
The return type for a lambda is specified using a C++ feature named 'trailing return type'. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively 'auto', and it is deduced from the type of the expressions in the body's return statements.
Using Lambda ExpressionsThe lambda expression should have the same number of parameters and the same return type as that method.
The return type of a method in which lambda expression used in a return statement must be a functional interface.
2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5. 1).
Now obviously those two types are the same,
No, they're not. The type of every lambda expression is a unique, distinct type.
From [expr.prim.lambda]/3:
The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below.
Therefore, return type deduction for f
fails and does not result in std::function<int()>
. The latter is an unrelated library type that isn't somehow magically the "common type" of any closure type.
Of course each of the unique closure types can be converted to std::function<int()>
, so if you provide the return type, everything works:
auto f = []() -> std::function<int()> {
return 1 ? []() { return 1; }
: []() { return 2; };
};
Or, as a plain function:
std::function<int()> f() {
return 1 ? []() { return 1; }
: []() { return 2; };
}
Every lambda has its own, unique type:
The lambda expression constructs an unnamed prvalue temporary object of unique unnamed non-union non-aggregate type[...].
From here, emphasize mine.
Also, lambdas have nothing to do with std::function
, that is another different type. In particular,
[] { return 1; }
and
[] { return 2; }
have different types. This is why deduction fails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With