Topic: Lambdas for container comparison functions
Author: daniel.kruegler@googlemail.com
Date: Tue, 19 May 2009 10:00:46 CST Raw View
On 15 Mai, 21:14, Scott Meyers <use...@aristeia.com> wrote:
> [..] I had forgotten that the closure class declares a non-default
> constructor when there are captures so that the captured
> variables can be used to initialize the data members of the
> closure. (Actually, I don't see wording to this effect in N2800,
> but I do see wording that generates copy and move constructors,
> and that's enough to prevent default-constructibility.)
In fact there is some work in progress to solve some current wording
problems of lambdas, see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2859.pdf
This paper solves e.g. the unclear position of the default c'tor (see
page
6 para 18 of the document) by requiring the existence of a *deleted*
default constructor.
> Would there be a problem with saying that the closure class has a
> "=default"
> default constructor when the effective capture set is empty?
This seems to be an excellent idea to me.
Greetings from Bremen,
- Daniel
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: vandevoorde@gmail.com
Date: Tue, 19 May 2009 15:38:00 CST Raw View
On May 12, 12:12 pm, Scott Meyers <use...@aristeia.com> wrote:
> Suppose I'd like to use a lambda expression to specify the comparison
> function
> for a set. I'd like to be able to say something like
>
> std::set<int*, decltype([](int *pa, int *pb) { return *pa < *pb; })>
> mySet;
>
> but I don't think this is legal, because I don't see a guarantee in 5.1.1
> (Lambda Expressions) that closures are default-constructible.
In addition, lambda expressions in decltype are probably going to be
banned: They present overly difficult implementation difficulties in
practice (e.g., it would require complete lambda bodies to be uniquely
mangled).
See also N2859.
Daveed
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <usenet@aristeia.com>
Date: Tue, 12 May 2009 10:12:00 CST Raw View
Suppose I'd like to use a lambda expression to specify the comparison
function
for a set. I'd like to be able to say something like
std::set<int*, decltype([](int *pa, int *pb) { return *pa < *pb; })>
mySet;
but I don't think this is legal, because I don't see a guarantee in 5.1.1
(Lambda Expressions) that closures are default-constructible.
Presumably this (or something similar) would work:
auto cmpFnc = [](int *pa, int *pb) { return *pa < *pb; }
std::set<int*, decltype(cmpFnc)> mySet(cmpFnc);
Is there a better way to use a lambda to specify a container's
comparison function?
Thanks,
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nick Mocha <nicmoc@gmail.com>
Date: Wed, 13 May 2009 10:10:18 CST Raw View
> I don't see a guarantee in 5.1.1
> (Lambda Expressions) that closures are default-constructible.
Given only the type of a lambda expression, what specific instance
of a lambda function might we reasonably expect to default
construct?
> Is there a better way to use a lambda to specify a container's
> comparison function?
Perhaps no better, but at least the no worse bits are isolated and for
reuse:
template <class T, class Cmp>
std::set<T, Cmp> makeSet(Cmp cmp)
{
return std::set<T, Cmp>(cmp);
}
void f()
{
auto ss = makeSet<int*>([](int *pa, int* pb){ return *pa <
*pb; });
}
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <usenet@aristeia.com>
Date: Wed, 13 May 2009 21:22:29 CST Raw View
Nick Mocha wrote:
>
> Given only the type of a lambda expression, what specific instance
> of a lambda function might we reasonably expect to default
> construct?
We'd expect to default-construct the type of the closure defined by
the lambda, which is the same behavior you get with every comparison
function type. Off the top of my head, it seems to me that a closure
type should be default-constructible unless it holds a copy of a
captured variable whose type is itself not default-constructible.
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: SG <s.gesemann@gmail.com>
Date: Thu, 14 May 2009 11:15:03 CST Raw View
On 12 Mai, 18:12, Scott Meyers <use...@aristeia.com> wrote:
> Suppose I'd like to use a lambda expression to specify the comparison
> function
> for a set. I'd like to be able to say something like
>
> std::set<int*, decltype([](int *pa, int *pb) { return *pa < *pb; })>
> mySet;
>
> but I don't think this is legal, because I don't see a guarantee in 5.1.1
> (Lambda Expressions) that closures are default-constructible.
Lambdas have a deleted default-constructor and a deleted copy-
assignment operator (according to N2859 "New wording for C++0x
lambdas"). Also, a lambda expression can't directly appear in
decltype, sizeof, alignof.
Theoretically, a lambda object could be default-constructible in case
its capture set is empty or only contains variables that are captured
by value and have been initialized with constant expressions. But I
don't think that this would buy you a lot.
From what I understand your 2nd example should compile:
> auto cmpFnc = [](int *pa, int *pb) { return *pa < *pb; }
> std::set<int*, decltype(cmpFnc)> mySet(cmpFnc);
Cheers!
SG
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nick Mocha <nicmoc@gmail.com>
Date: Thu, 14 May 2009 13:13:34 CST Raw View
> > Given only the type of a lambda expression, what specific instance
> > of a lambda function might we reasonably expect to default
> > construct?
>
> We'd expect to default-construct the type of the closure defined by
> the lambda, which is the same behavior you get with every comparison
> function type.
The standard functional predicates can be default constructed. For
these
predicates, the type _is_ the function. But the type need not be
one-one to actual function, e.g., this single type can implement many
functions:
typedef bool(*Cmp)(int, int);
struct Compare : public std::binary_function<int, int, bool> {
Cmp cmp_;
bool operator()(int x, int y) { return (*cmp_)(x, y); }
};
bool someFunction(int x, int y) { return x < y; }
int main() {
Compare compare;
compare.cmp_ = someFunction;
std::set<int, decltype(compare)> s;
s.insert(1);
s.insert(2); // trouble
}
So, in general, we cannot go from an object, to its type, then back
to
an object similar to the first, even though we can for the standard
predicates.
> Off the top of my head, it seems to me that a closure
> type should be default-constructible unless it holds a copy of a
> captured variable whose type is itself not default-constructible.
Isn't that rather like saying that all classes should have a default
constructor
that default constructs its members, even when a non-default
constructor has
been supplied? We'd then all have to explicitly opt out of default
construction,
like we might do for copy construction and assignment.
The closure is non-default constructed by capturing, default
construction, as for
most things with only non-default constructors, leads to surprises.
template <class Lambda>
void trouble(Lambda unused) {
Lambda newLambda; // where's cmp
newLambda(1, 2); // trouble?
}
int fun(Cmp cmp) {
auto lambda = [=](int x, int y){ return cmp(x, y); };
trouble(lambda);
}
Of the top of my head off the top of your head, it seems that a
closure
type might be default-constructible only if it captures nothing (i.e.
default constructs itself, not it's 'members'). Thus consistency
with the class objects and standard predicates is regained.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Scott Meyers <usenet@aristeia.com>
Date: Fri, 15 May 2009 13:14:14 CST Raw View
Nick Mocha wrote:
> Of the top of my head off the top of your head, it seems that a
> closure
> type might be default-constructible only if it captures nothing (i.e.
> default constructs itself, not it's 'members'). Thus consistency
> with the class objects and standard predicates is regained.
The top of your head is better than the top of mine. I had forgotten
that the
closure class declares a non-default constructor when there are captures
so that
the captured variables can be used to initialize the data members of the
closure. (Actually, I don't see wording to this effect in N2800, but I
do see
wording that generates copy and move constructors, and that's enough to
prevent
default-constructibility.)
Would there be a problem with saying that the closure class has a
"=default"
default constructor when the effective capture set is empty?
Scott
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]