Familiar template syntax for generic lambdas
The result of a lambda expression is not a function; it is a function object. That is, it is a class type that has an operator()
overload on it. So this:
auto f = []<typename T>( T t ) {};
Is equivalent to this:
struct unnamed
{
template<typename T>
void operator()(T t) {}
};
auto f = unnamed{};
If you want to explicitly provide template arguments to a lambda function, you have to call operator()
explicitly: f.operator()<template arguments>(parameters);
.
Is (or will be) the use of familiar template syntax in lambda expressions allowed?
The version of the paper that was accepted was N3649
, we can see this by going to Evolution Working Group(EWG) Completed Issue 16: N3649, N3560, N3559, N3418 Proposal for Generic (Polymorphic) Lambda Expressions:
Reviewed by EWG in Portland 2012, proceeding with a follow-up paper.
Accepted into the Working Draft in Bristol 2013, as N3649.
Bristol 2013: Do not re-open proposals 2.1 and 2.2 in N3560, they are
considered NAD. The proposals 2.3 and 2.4 are covered by N3649.
Note this references proposal 2.1
and 2.2
as being NAD(Not A Defect) and that they won't be reopened. N3560
was split off from N3418
which was the main proposal and proposal 2.1
in N3560
was:
Allow the use of familiar template syntax in lambda expressions
that paper notes proposal 2.1
was considered controversial:
We admit that supporting the full template parameter list feature
has been deemed controversial (the Portland 2012 straw-poll outcomes
were: 7 SF, 5 F, 3 N, 1 A, 1 SA 1 ) by a few committee members, and
therefore conclude this sub-section with some quotes from a committee
member who was not present in the room during EWG's discussion of
this feature in Portland.
and we can see that N3649 does not contain this proposal my guess from the quote in paper N3560
:
"
I think we need more than just
auto. I'm not sure how much more, but I think having just auto would be too limiting
".
was that auto was considered sufficient in the end which would be consistent with saying that the proposal is NAD
meaning the issue it attempted to resolve is not really an issue.
C++20 template lambda: how to specify template argument?
foo.template operator()<true>();
is the correct syntax. Try it on godbolt.org
The reason for this strange syntax is because:
foo
is a generic lambda which implements atemplate<bool> operator()
method.foo.operator()<true>()
would interpret<
as a comparison operator.
If you want a slightly more readable syntax, try using a std::bool_constant
:
auto foo = []<bool arg>(std::bool_constant<arg>) {
...
};
foo(std::bool_constant<true>{});
Try it on godbolt.org
What is the need of template lambda introduced in C++20 when C++14 already has generic lambda?
C++14 generic lambdas are a very cool way to generate a functor with an operator ()
that looks like this:
template <class T, class U>
auto operator()(T t, U u) const;
But not like this:
template <class T>
auto operator()(T t1, T t2) const; // Same type please
Nor like this:
template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please
Nor like this (although this gets a bit tricky to actually use):
template <class T>
auto operator()() const; // No deduction
C++14 lambdas are fine, but C++20 allows us to implement these cases without hassle.
Explicit instantiation of templated lambda
check
itself is not a template. It is an object, of an unspecified closure type, that contains
template<auto I> void operator()();
The member function is the template.
The error is due to the attempt at supplying template arguments to check
. Which is not a template itself, again. The template parameters of a lambda's function call operator need to be deducible (even if they are named), for the function call syntax to work. That hasn't changed with C++20.
The only way to specify the parameters explicitly is the pretty ugly
check.template operator()<II>()
But instead it may be better to make it deducible.
[&]<auto... II>(std::index_sequence<II...>) {
auto check = [&]<auto I>(std::integral_constant<decltype(I), I>){
};
(check(std::integral_constant<decltype(II), II>{}),...);
}(std::make_index_sequence<N>{});
Specifying size_t
explicitly is also an option instead of using decltype(I)
.
Why are C++20 template lambdas using typename keyword?
The problem is that this already has a meaning:
template <T> void foo();
It's a function template with one template parameter that is a non-type template parameter whose type is T
, and that template parameter has no name.
It would be pretty confusing if the same syntax meant very different things depending on if you're introducing a function template or a generic lambda -- which is to say, two very similar contexts serving similar purposes!
Plus then... what would you do if you actually want a non-type template parameter? Just can't have one?
C++ specialize a lambda for a certain type
This type of coding may seem superfluous at first but there are some nice properties we can take advantage of. Regarding the post you mention, I was planning on a part 2, where I'd showcase a neat way of checking whether a type has a specific member (function or data). Say you want to check for a serialize
member function; instead of using complicated mechanisms I discovered it gets as easy as :
auto hs = overload(
[ ](auto&& x) -> decltype(x.serialize(2), std::true_type{}) {
return{}; }, // ^^ this guy ^^
[ ](...) -> std::false_type { return {}; });
demo
The specifics of standardese evolution can be found here, but the reason I posted this is to advocate for such a syntax which, had we have had it, the above could be extended to allow partial ordering among "overloaded" generic lambdas :
auto do_something = overload(
[ ]<class X>(shared_ptr<X> x) -> decltype(x.serialize(2), std::true_type{}) {
/*do something specific for shared ptrs of X */ return{}; },
[ ]<class X>(X& x) -> decltype(x.serialize(2), std::true_type{}) {
/*do a generic operation for other types that have serialize*/return{}; },
[ ](...) -> std::false_type { /*do nothing*/ return {}; });
Related Topics
How to Restart My Own Qt Application
Maximum Stack Size for C/C+ Program
Is There Any Use for Local Function Declarations
Assembly Adc (Add with Carry) to C++
Undefined Reference to Winmain (C++ Mingw)
Is It Bad Practice to Allocate Memory in a Dll and Give a Pointer to It to a Client App
Printf Rounding Behavior for Doubles
Write and Read String to Binary File C++
Boost::Spirit Expression Parser
Boost.Python Not Supporting Parallelism
How to Get a Color Palette from an Image Using Opencv
How to Use Boost Preprocessor to Generate Accessors
Structured Binding with [[Maybe_Unused]]
Differencebetween Using a Struct with Two Fields and a Pair
How to Use Non-Default Delimiters When Reading a Text File with Std::Fstream