Discussion:
Lambda in STL compare
(too old to reply)
M***@DastartdlyHQ.org
2024-10-07 07:32:02 UTC
Permalink
Isn't it about time that lambda functions could be used directly as STL
comparitors instead of it being an ugly 2 step process?

ie instead of:

auto comp = [](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
};
map<string,int,decltype(comp)> m(comp);

which is no simpler than just using a functor, why can't we just do:

map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;

I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.

Rather than adding esoteric functionality no one uses wouldn't it be better
to tidy up what there is already?
Bonita Montero
2024-10-07 08:12:03 UTC
Permalink
Post by M***@DastartdlyHQ.org
Isn't it about time that lambda functions could be used directly as STL
comparitors instead of it being an ugly 2 step process?
auto comp = [](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
};
map<string,int,decltype(comp)> m(comp);
map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;
I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.
Rather than adding esoteric functionality no one uses wouldn't it be better
to tidy up what there is already?
Lambdas can be used in an unevaluated context since C++20, i.e
you could write <, decltype([]( ... ) { })> as you did. Try it
with -std=c++20 / -std:c++29.
M***@DastartdlyHQ.org
2024-10-07 09:32:52 UTC
Permalink
On Mon, 7 Oct 2024 10:12:03 +0200
Post by Bonita Montero
Post by M***@DastartdlyHQ.org
Isn't it about time that lambda functions could be used directly as STL
comparitors instead of it being an ugly 2 step process?
auto comp = [](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
};
map<string,int,decltype(comp)> m(comp);
map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;
I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.
Rather than adding esoteric functionality no one uses wouldn't it be better
to tidy up what there is already?
Lambdas can be used in an unevaluated context since C++20, i.e
you could write <, decltype([]( ... ) { })> as you did. Try it
with -std=c++20 / -std:c++29.
I did, didn't work. But then the version of clang in MacOS is always behind
the times. It supports the -std=c++20 option but doesn't seem to honour all
of the 2020 spec yet.

Anyway, good to know thats been sorted.
David Brown
2024-10-07 08:16:46 UTC
Permalink
Post by M***@DastartdlyHQ.org
Isn't it about time that lambda functions could be used directly as STL
comparitors instead of it being an ugly 2 step process?
auto comp = [](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
};
map<string,int,decltype(comp)> m(comp);
map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;
I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.
Rather than adding esoteric functionality no one uses wouldn't it be better
to tidy up what there is already?
After fixing the typos (you missed part of the "decltype"), it compiles
fine:

map<string, int, decltype([](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(), s2.c_str()) < 0;
})> m;


(Warning - I've only compiled this on godbolt, not tested it to see if
it works!)


The key point is that in C++20, lambda closures got a default
constructor if they have no captures.

It would, however, be even nicer if there were no need for "decltype" here.
Sam
2024-10-07 11:35:34 UTC
Permalink
Post by M***@DastartdlyHQ.org
map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;
I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.
The reason we cannot do that is because the third parameter to std::map is a
type, and not an object. A lambda expression is an instance of an anonymous
type, and not a type in of itself.
M***@DastartdlyHQ.org
2024-10-07 14:06:41 UTC
Permalink
On Mon, 07 Oct 2024 07:35:34 -0400
Post by Sam
Post by M***@DastartdlyHQ.org
map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;
I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.
The reason we cannot do that is because the third parameter to std::map is a
type, and not an object. A lambda expression is an instance of an anonymous
type, and not a type in of itself.
Its a definition, not a value, so why can't it silently be converted internally
by the compiler? Presumably it does just that when it sees decltype anyway.
Bonita Montero
2024-10-07 14:13:48 UTC
Permalink
Its a definition, not a value, ...
Wrong, a lambda is a PR-value.
M***@DastartdlyHQ.org
2024-10-07 14:53:08 UTC
Permalink
On Mon, 7 Oct 2024 16:13:48 +0200
Post by Bonita Montero
Its a definition, not a value, ...
Wrong, a lambda is a PR-value.
I don't see why it can't be cast to std::function. It is a function after all.
Bonita Montero
2024-10-07 15:06:11 UTC
Permalink
Post by M***@DastartdlyHQ.org
On Mon, 7 Oct 2024 16:13:48 +0200
Post by Bonita Montero
Its a definition, not a value, ...
Wrong, a lambda is a PR-value.
I don't see why it can't be cast to std::function. It is a function after all.
Of course you can cast it to a compatible function, i.e. the parmeters
of the lambda and the parameter supplied to the function must match.
M***@DastartdlyHQ.org
2024-10-07 15:46:08 UTC
Permalink
On Mon, 7 Oct 2024 17:06:11 +0200
Post by Bonita Montero
Post by M***@DastartdlyHQ.org
On Mon, 7 Oct 2024 16:13:48 +0200
Post by Bonita Montero
Its a definition, not a value, ...
Wrong, a lambda is a PR-value.
I don't see why it can't be cast to std::function. It is a function after
all.
Of course you can cast it to a compatible function, i.e. the parmeters
of the lambda and the parameter supplied to the function must match.
The compiler knows exactly what the parameters are. Try thinking outside
of the box. The semantic rules are not immutable laws of physics.
Bonita Montero
2024-10-07 15:55:14 UTC
Permalink
The compiler knows exactly what the parameters are. ..
The parameters of a function-object must be convertible to
those of the lambda. That's all.
M***@DastartdlyHQ.org
2024-10-08 08:23:45 UTC
Permalink
On Mon, 7 Oct 2024 17:55:14 +0200
Post by Bonita Montero
The compiler knows exactly what the parameters are. ..
The parameters of a function-object must be convertible to
those of the lambda. That's all.
So make it convertable. I find it perverse that the declaration of a struct/
class and the declaration of a function/lambda are considered different types
of declarations. The compiler should see that its being used in a template and
act accordingly.
Bonita Montero
2024-10-08 08:25:33 UTC
Permalink
Post by M***@DastartdlyHQ.org
So make it convertable. I find it perverse that the declaration of a struct/
class and the declaration of a function/lambda are considered different types
of declarations. ..
In one case you have a variable-_defintiion_, in the other a declaration.
M***@DastartdlyHQ.org
2024-10-08 10:24:32 UTC
Permalink
On Tue, 8 Oct 2024 10:25:33 +0200
Post by Bonita Montero
Post by M***@DastartdlyHQ.org
So make it convertable. I find it perverse that the declaration of a struct/
class and the declaration of a function/lambda are considered different types
of declarations. ..
In one case you have a variable-_defintiion_, in the other a declaration.
No, they're both declarations. The only difference is how you assign them
to variables.

[](whatever) { }

is not a variable, its a definition.

auto lambda = [](whatever) { }

is a variable declaration and assignment.
Bonita Montero
2024-10-08 11:10:33 UTC
Permalink
Post by M***@DastartdlyHQ.org
On Tue, 8 Oct 2024 10:25:33 +0200
Post by Bonita Montero
Post by M***@DastartdlyHQ.org
So make it convertable. I find it perverse that the declaration of a struct/
class and the declaration of a function/lambda are considered different types
of declarations. ..
In one case you have a variable-_defintiion_, in the other a declaration.
No, they're both declarations. ..
No, the implcit definition isn't usually seen, but just with a decltype().
Sam
2024-10-08 12:25:33 UTC
Permalink
Post by M***@DastartdlyHQ.org
On Mon, 07 Oct 2024 07:35:34 -0400
Post by Sam
The reason we cannot do that is because the third parameter to std::map is a
type, and not an object. A lambda expression is an instance of an anonymous
type, and not a type in of itself.
Its a definition, not a value, so why can't it silently be converted internally
by the compiler? Presumably it does just that when it sees decltype anyway.
Because it's not the compiler's job to invent new templates. If there was an
overloaded template whose third parameter is an object, then, I suppose,
things will work this way. But there isn't one.
M***@DastartdlyHQ.org
2024-10-08 14:44:48 UTC
Permalink
On Tue, 08 Oct 2024 08:25:33 -0400
Post by Sam
Post by M***@DastartdlyHQ.org
On Mon, 07 Oct 2024 07:35:34 -0400
Post by Sam
The reason we cannot do that is because the third parameter to std::map is a
type, and not an object. A lambda expression is an instance of an anonymous
type, and not a type in of itself.
Its a definition, not a value, so why can't it silently be converted internally
by the compiler? Presumably it does just that when it sees decltype anyway.
Because it's not the compiler's job to invent new templates. If there was an
Its the compilers job to interpret the template. Given the semantic hoops,
gotchas,hacks and generalinconsistencies C++ already has, another one that
might actually be useful isn't going to hurt.
Sam
2024-10-08 21:52:25 UTC
Permalink
Post by M***@DastartdlyHQ.org
On Tue, 08 Oct 2024 08:25:33 -0400
Post by Sam
Because it's not the compiler's job to invent new templates. If there was an
Its the compilers job to interpret the template. Given the semantic hoops,
gotchas,hacks and generalinconsistencies C++ already has, another one that
might actually be useful isn't going to hurt.
Hm, I'm beginning to think you're right. After all, C++ has always had a
reputation of being too simplistic, straightforward, and easy to learn and
understand. It's about time some complexity was added to the language.
Chris M. Thomasson
2024-10-09 05:56:56 UTC
Permalink
Post by Sam
Post by M***@DastartdlyHQ.org
On Tue, 08 Oct 2024 08:25:33 -0400
Post by Sam
Because it's not the compiler's job to invent new templates. If there
was an
Its the compilers job to interpret the template. Given the semantic hoops,
gotchas,hacks and generalinconsistencies C++ already has, another one that
might actually be useful isn't going to hurt.
Hm, I'm beginning to think you're right. After all, C++ has always had a
reputation of being too simplistic, straightforward, and easy to learn
and understand. It's about time some complexity was added to the language.
Yikes! ;^)
M***@DastartdlyHQ.org
2024-10-09 07:15:03 UTC
Permalink
On Tue, 08 Oct 2024 17:52:25 -0400
Post by Sam
Post by M***@DastartdlyHQ.org
On Tue, 08 Oct 2024 08:25:33 -0400
Post by Sam
Because it's not the compiler's job to invent new templates. If there was an
Its the compilers job to interpret the template. Given the semantic hoops,
gotchas,hacks and generalinconsistencies C++ already has, another one that
might actually be useful isn't going to hurt.
Hm, I'm beginning to think you're right. After all, C++ has always had a
reputation of being too simplistic, straightforward, and easy to learn and
understand. It's about time some complexity was added to the language.
I happen to think the removal of the need for decltype() would actually
simplify things. Are there any instances where a piece of code would compile
with and without decltype but otherwise is identical? If not then what harm
would it do to make the compiler infer its a type instead of having to
be explicily told? After all, thats the rationale behind "auto".
Bonita Montero
2024-10-09 07:21:50 UTC
Permalink
Post by M***@DastartdlyHQ.org
I happen to think the removal of the need for decltype() would actually
simplify things. ...
It wouldn't make sense since a lambda is a pr-_value_ !
M***@DastartdlyHQ.org
2024-10-09 07:22:50 UTC
Permalink
On Wed, 9 Oct 2024 09:21:50 +0200
Post by Bonita Montero
Post by M***@DastartdlyHQ.org
I happen to think the removal of the need for decltype() would actually
simplify things. ...
It wouldn't make sense since a lambda is a pr-_value_ !
Whooosh....
M***@DastartdlyHQ.org
2024-10-09 07:16:40 UTC
Permalink
On Tue, 08 Oct 2024 17:52:25 -0400
Post by Sam
Post by M***@DastartdlyHQ.org
On Tue, 08 Oct 2024 08:25:33 -0400
Post by Sam
Because it's not the compiler's job to invent new templates. If there was an
Its the compilers job to interpret the template. Given the semantic hoops,
gotchas,hacks and generalinconsistencies C++ already has, another one that
might actually be useful isn't going to hurt.
Hm, I'm beginning to think you're right. After all, C++ has always had a
reputation of being too simplistic, straightforward, and easy to learn and
understand. It's about time some complexity was added to the language.
That horse bolted and disappeared over the horizon long ago. I suspect any
kid or student looking at which programming language to learn would take
one look at modern C++ and flee to Pythonville as fast as he could.
Chris M. Thomasson
2024-10-09 07:23:13 UTC
Permalink
Post by M***@DastartdlyHQ.org
On Tue, 08 Oct 2024 17:52:25 -0400
Post by Sam
Post by M***@DastartdlyHQ.org
On Tue, 08 Oct 2024 08:25:33 -0400
Post by Sam
Because it's not the compiler's job to invent new templates. If there was an
Its the compilers job to interpret the template. Given the semantic hoops,
gotchas,hacks and generalinconsistencies C++ already has, another one that
might actually be useful isn't going to hurt.
Hm, I'm beginning to think you're right. After all, C++ has always had a
reputation of being too simplistic, straightforward, and easy to learn and
understand. It's about time some complexity was added to the language.
That horse bolted and disappeared over the horizon long ago. I suspect any
kid or student looking at which programming language to learn would take
one look at modern C++ and flee to Pythonville as fast as he could.
Python 2 or 3? ;^)

Andrey Tarasevich
2024-10-07 14:17:32 UTC
Permalink
Post by M***@DastartdlyHQ.org
Isn't it about time that lambda functions could be used directly as STL
comparitors instead of it being an ugly 2 step process?
auto comp = [](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
};
map<string,int,decltype(comp)> m(comp);
map<string,int,[](const string &s1, const string &s2)
{
return strcasecmp(s1.c_str(),s2.c_str()) < 0;
}) m;
I'm sure updating the compilers so a lambda could be a template parameter
wouldn't be beyond the wit of man.
Firstly, the suggested resolution does not make any sense. Lambda
expression produces a value. Why are you stuffing into a location that
expects a type?

Secondly, the language already provides a promising _potential_
solution: class template deduction. Which means that theoretically one
might dream about being able to do

std::map<std::string, int> m(comp);

without having to specify the type of `comp` in the template argument
list, i.e. expecting the compiler to deduce the proper comparator type.

However, firstly, at this time the deduction kicks only when no template
argument is specified for the template. I.e. there's no partial
deduction. And, secondly, this clashes with the current specification of
`std::map`, which provides the default argument for the comparator
parameter (as `std::less`).

But even today you can do this:

template <typename C>
using si_map = std::map<std::string, int, C>;

si_map m(comp);

and it works.

Maybe in the future class template parameter deduction will become more
flexible... Or maybe there's a more elegant workaround to enable
something like that today, which I just don't see.
--
Best regards,
Andrey
Loading...