any plans for alowing templates to take lambdas as parameters

163 views
Skip to first unread message

nx02co...@gmail.com

unread,
May 31, 2013, 9:12:18 AM5/31/13
to std-pr...@isocpp.org
Hi,
I know reasons why lambdas cant be used as template arguments atm(lambda is not a type, jada jada, decltype... - http://stackoverflow.com/questions/5849059/lambda-expressions-as-class-template-parameters) ,
 but as a usability feature it would be a great addition to C++.
This way it is "unusable", aka it is simpler just to make a named function.

Daniel Krügler

unread,
May 31, 2013, 9:14:24 AM5/31/13
to std-pr...@isocpp.org
2013/5/31 <nx02co...@gmail.com>:
> Hi,
> I know reasons why lambdas cant be used as template arguments atm(lambda is
> not a type, jada jada, decltype... -
> http://stackoverflow.com/questions/5849059/lambda-expressions-as-class-template-parameters)

If you know the "why", what is your complain?

> but as a usability feature it would be a great addition to C++.
> This way it is "unusable", aka it is simpler just to make a named function.

This is a possible solution, yes.

- Daniel

Nicol Bolas

unread,
May 31, 2013, 10:00:49 AM5/31/13
to std-pr...@isocpp.org, nx02co...@gmail.com

And what exactly is wrong with making a named function? What is it with people and their need to use lambdas for everything? I know lambdas are your sexy new C++11 feature, but really, what is the problem with using a specific type that has a real name?

struct name { void operator()() {} };

Why is this so hard to do?

Martinho Fernandes

unread,
May 31, 2013, 10:26:51 AM5/31/13
to std-pr...@isocpp.org
I hope I am missing something here, because all this talk about lambdas as template arguments improving usability sounds like nonsense to me. What can you do with a lambda type that makes them so usable as template arguments?

Without requiring lambda types to be default-constructible, I don't see how this makes anything more usable.

using my_set = std::set<int, decltype([](int x, int y) { return f(x) < f(y); })>;
my_set haha_nice_try; // nope, error
my_set some_set([](int x, int y) { return f(x) < f(y); }); // erm, error!
my_set some_other_set([](int x, int y) { return f(x) < f(y); }); // ok, let's assume at least lambdas identical character-by-character are the same type; then this works

What? I have to repeat the function definition *everywhere*? And that doesn't work anyway? No, thanks.
Of course, I can just declare the lambda as a global variable instead:

auto comparison = [](int x, int y) { return f(x) < f(y); };
using my_set = std::set<int, decltype(comparison)>;
my_set haha_nice_try; // nope, still an error
my_set some_set(comparison); // ok, now this works
my_set some_other_set(comparison); // but don't you forget to pass the comparison along every single time lest you unless the compiler's wrath upon you!

Stop it. This has no interesting advantage over using a function.

bool comparison(int x, int y) { return f(x) < f(y); };
using my_set = std::set<int, decltype(comparison)>;
my_set haha_nice_try; // also an error!
my_set some_set(comparison); // has always worked
my_set some_other_set(comparison); // keep not forgetting it!

Note how the comparison is not really entirely part of the set. You have to keep passing it along anytime you create one. That sucks.

struct my_comparison {
    bool operator()(int x, int y) { return f(x) < f(y); }
};

using my_set = std::set<int, my_comparison>;
my_set haha_nice_try; // hey, it works
my_set some_set(my_comparison{}); // you can, but why would you?
my_set some_other_set;

Note how the proposal to get lifted functions would also be cool here.

bool comparison
(int x, int y) { return f(x) < f(y); };
using my_set = std::set<int, decltype([]comparison)>;
my_set haha_nice_try;
my_set some_set;
my_set some_other_set; // all work fine

Mit freundlichen Grüßen,

Martinho


--
 
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
 
 

Daniel Krügler

unread,
May 31, 2013, 10:32:40 AM5/31/13
to std-pr...@isocpp.org
2013/5/31 Martinho Fernandes <martinho....@gmail.com>:
> I hope I am missing something here, because all this talk about lambdas as
> template arguments improving usability sounds like nonsense to me. What can
> you do with a lambda type that makes them so usable as template arguments?

My assumption was that the OP was concerned about the restriction that
lambda *expressions* cannot appear in an unevaluated operand.

We also have the following core language issue related to that

www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1607

- Daniel
Message has been deleted

Mikhail Semenov

unread,
Jun 2, 2013, 8:16:52 AM6/2/13
to std-pr...@isocpp.org
With lambda autos or templates I will be able to do this:
class B
{   
    std::vector<double> y;
public:
    B(const std::vector<double>& y1);
      
    std::vector<double> add_vector(std::vector<double>&& z);
   
    std::vector<double> add_vector(const std::vector<double>& z) const;      
};
 
#define member_delegate(_a,_fn)\
[&](auto&& ... _x)\
{\
    return (_a)._fn(std::forward<decltype(_x)>(_x) ...);\
}
 
or maybe(???)
 
#define member_delegate(_a,_fn)\
template <class ... _Args>\
[&](_Args&& ... _x)\
{\
    return (_a)._fn(std::forward<_Args>(_x) ...);\
}

Some statements:
 
B b1(some_vector);
auto b_add = member_delegate(b1,add_vector);
std::vector<double> v1 = b_add(v); // add_vector(const std::vector<double>& z) const
std::vector<double> v2 = b_add(std::move(v)); // selects add_vector(std::vector<double>&& z)

If autos work then probably templates are not needed.

Róbert Dávid

unread,
Jun 2, 2013, 7:53:18 PM6/2/13
to std-pr...@isocpp.org, nx02co...@gmail.com
Yay, another soul with the same "problems" :)

I have made a proposal about default-constructing closures, back in march, but 5.1.2 [expr.prim.lambda] paragraph 2 makes it effectively useless - although it works fine with MSVC10 (e.g. a std::map with a lambda comparator, passing the closure at construction), but not portable: even in MSVC11 it breaks. This one is the other way around, it is useless without default-constructed closures..

In the linked core issue, I like second solution - if you are using a lambda, you most probably want internal linkage anyway.

Regards, Robert

Martinho Fernandes

unread,
Jun 3, 2013, 7:29:24 AM6/3/13
to std-pr...@isocpp.org
On Sun, Jun 2, 2013 at 1:42 PM, Mikhail Semenov <mikhailse...@gmail.com> wrote:
With lambda autos or templates I will be able to do this:
 
class B
{   
    std::vector<double> y;
public:
    B(const std::vector<double>& y1);
      
    std::vector<double> add_vector(std::vector<double>&& z);
   
    std::vector<double> add_vector(const std::vector<double>& z) const;      
};
 
#define member_delegate(_a,_fn)\
[&](auto&& ... _x)\
{\
    return (_a)._fn(std::forward<decltype(_x)>(_x) ...);\
}
 
or maybe(???)

#define member_delegate(_a,_fn)\
template <class ... _Args>\
[&](_Args&& ... _x)\
{\
    return (_a)._fn(std::forward<_Args>(_x) ...);\
}

In main:
B b1(some_vector);
 
auto b_add = member_delegate(b1,add_vector);
 
std::vector<double> v1 = b_add(v); // selects add_vector(std::vector<double>&& z)
std::vector<double> v2 = b_add(std::move(v)); // selects add_vector(const std::vector<double>& z) const;
If autos work then probably templates are not needed.

What do you mean by "lambda autos"? Using lambdas to initialise type-inferred variables? We had that feature since C++11 (and it was available in various implementations way before that). I don't see any lambda types as template arguments or any lambda as an unevaluated argument there.

What that code seems to need is N3617.

Martinho Fernandes

unread,
Jun 3, 2013, 7:30:27 AM6/3/13
to std-pr...@isocpp.org
On Mon, Jun 3, 2013 at 1:29 PM, Martinho Fernandes <martinho....@gmail.com> wrote:
What that code seems to need is N3617.

For clarity, what N3617 enables here is first-class overloads, aka overloads-as-function-objects.

Mit freundlichen Grüßen,

Martinho

nx02co...@gmail.com

unread,
Jun 3, 2013, 9:32:40 AM6/3/13
to std-pr...@isocpp.org
How often do you need comparison function more than once ?
Me prob <10% of cases...
that is why lambda would be nice...
that said I like your examples and insight, thank you for taking time to write it.

Mikhail Semenov

unread,
Jun 3, 2013, 2:37:34 PM6/3/13
to std-pr...@isocpp.org
Martinho,
 
I am not aware of implementations that support even a single auto in a lambda
[&](auto x){ };
GCC 4.8.0 and Visual C++ 2012 don't.
 
C++11 does not supports "auto" in formal parameters (for functions or lambdas).
 
I am looking forward to using the N3649 features (Polymorphic Lambda).
 
As for 3617, I have to look at it more closely.
 
Regards,
 
Mikhail.


--

Richard Smith

unread,
Jun 3, 2013, 3:49:06 PM6/3/13
to std-pr...@isocpp.org
On Mon, Jun 3, 2013 at 11:37 AM, Mikhail Semenov <mikhailse...@gmail.com> wrote:
Martinho,
 
I am not aware of implementations that support even a single auto in a lambda
[&](auto x){ };
GCC 4.8.0 and Visual C++ 2012 don't.

There's an implementation of an earlier revision of the generic lambdas paper here:

Mikhail Semenov

unread,
Jun 4, 2013, 1:58:15 PM6/4/13
to std-pr...@isocpp.org
Thank you, Richard.
Reply all
Reply to author
Forward
0 new messages