Is the following code well-formed C++17?
template <typename T, int = [](auto t) { decltype(t)::invalid; return 0; }(T{})>
constexpr int f(T) { return 0; }
constexpr int f(...) { return 1; }
static_assert(f(0) == 1);
clang and edg accept it, while msvc and gcc1 reject it. I can't find anything that would say that this is a hard error, but I also can't find anything that would say that this is a deduction failure.
In C++20, there is this paragraph ([temp.deduct]p9):
A lambda-expression appearing in a function type or a template parameter is not considered part of the immediate context for the purposes of template argument deduction.
which makes it clear that the lambda is not part of the immediate context. But what about C++17?
1: gcc has a bug with auto
in this context, but rewriting it using explicit template parameters for the lambda gets you the same error.
In C++11 and later, a lambda expression—often called a lambda—is a convenient way of defining an anonymous function object (a closure) right at the location where it's invoked or passed as an argument to a function.
Permalink. All the alternatives to passing a lambda by value actually capture a lambda's address, be it by const l-value reference, by non-const l-value reference, by universal reference, or by pointer.
A type lambda lets one express a higher-kinded type directly, without a type definition. For instance, the type above defines a binary type constructor, which maps arguments X and Y to Map[Y, X] . Type parameters of type lambdas can have bounds, but they cannot carry + or - variance annotations.
From the various lambda improvements, template parameters for lambdas are my favorite ones. Lambdas support with C++20 template parameters, can be default-constructed and support copy-assignment, when they have no state, and can be used in unevaluated contexts.
It's plain ill-formed in C++17, if I gather correctly.
[expr.prim.lambda] (emphasis mine)
2 A lambda-expression shall not appear in an unevaluated operand, in a template-argument, [...]
[temp.param] (emphasis mine)
9 A default template-argument is a template-argument ([temp.arg]) specified after = in a template-parameter.
In both cases "template-argument" is the same normative term. So I think Clang and edg err by accepting the code in the OP as valid C++17.
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