Consider the following which uses the ternary operator to get the common function pointer type of the two lambdas
int main() {
true ? [](auto) noexcept {} : [](int) {};
}
GCC-trunk only accepts it in C++14 but rejects it in C++17/20 with (Demo):
<source>:2:8: error: operands to '?:' have different types 'main()::<lambda(auto:1)>' and 'main()::<lambda(int)>'
2 | true ? [](auto) noexcept {} : [](int) {};
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Clang-trunk accepts it in all C++14/17/20 mode (Demo).
MSVC-trunk only accepts it in C++20 but rejects it in C++14/17 with (Demo):
<source>(2): error C2446: ':': no conversion from 'main::<lambda_01e5bb79b5a210014fb78333f6af80f9>' to 'main::<lambda_57cf6f5767bc1bee4c1e1d9859a585d2>'
<source>(2): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Which compiler is right?
Since each lambda expression has a unique type, and neither lambda expression is convertible to the other, [expr.cond]/6 applies.
The candidates are ([over.built]/25):
I believe that overload resolution should succeed in this case, and as a result, both operands should be converted to
void(*)(int)
.That is, IMO clang is correct.
Edit: I believe that
[](auto) noexcept {}
is convertible tovoid(*)(int)
, because it has a conversion function templatetemplate<class T> operator FP()
, whereFP
isvoid(*)(T)
([expr.prim.lambda.closure]/9).And I believe that template argument deduction should make this conversion template usable as a conversion to
void(*)(int)
([temp.deduct.conv]/5).