MSVC 2019 allow me to define a lambda like this, where the template argument is not used in the parameter list:
auto foo = []<bool B>() {
return B;
};
However, it gives syntax error when trying to call it like this?
foo<false>();
What is the correct way to call a lambda with a non-parameter template argument?
CodePudding user response:
The template parameter is used with operator()
of lambda.
(since C 20) If the lambda definition uses an explicit template parameter list, that template parameter list is used with operator().
You can specify the non-type template argument for operator()
, call the lambda in an unnormal style as:
foo.operator()<false>();
CodePudding user response:
foo
is a function object. It has an operator()
. The template on a lambda is on that operator, not on the object name itself.
foo<T>
attempts to give the name foo
a template argument T
; that isn't valid here. foo<T>()
gives the template argument to foo
, then calls ()
on the result. Again, not what is going on here.
A template variable would work the way you want this to:
template<bool B>
auto foo = []() {
return B;
};
such variables only work in global scope, but here foo<true>()
would work.
As a lambda is actually a compiler-generate class:
struct some_secret_name {
template<bool B>
auto operator()() const {
return B;
}
};
some_secret_name foo;
then the "right" way to call it is the ugly syntax:
foo.operator()<true>();
this, honestly, sucks.
You can get slightly better syntax like this:
template<class T> struct tag_t {using type=T;};
template<class T> constexpr tag_t<T> tag_v={};
template<auto v> using value_t = std::integral_constant<std::decay_t<decltype(v)>, v>;
template<auto v> constexpr value_t<v> value_v={};
then we can do
auto foo = []<bool B>(value_t<B>) {
return []{
return B;
};
};
now the syntax is:
foo(value_v<false>)();
which looks a bit less cludgy, if overly magical.
foo
is now a lambda that makes lambdas, the outer lambda takes your template parameters as function arguments, and the inner lambda is the body.