1

Do C++14 generic lambdas bring a real improvement to the language or they are a kind of syntactic sugar? Whether there are some situations where

[](auto param1, auto param2, /* ... */ auto paramN)
{
    return /* ... */;
}

cannot be replaced with

template <typename Type1, typename Type2, /* ... */ typename TypeN>
auto foo(Type1&& param1, Type2&& param2, /* ... */ TypeN&& paramN)
{
    return  /* ... */;
}

or

struct bar
{
    template <typename Type1, typename Type2, /* ... */ typename TypeN>
    auto operator()(Type1&& param1, Type2&& param2, /* ... */ TypeN&& paramN)
    {
        return  /* ... */;
    }
};

?


@Kerrek SB provided very interesting links in the comments which illustrate the power of generic lambdas:

Community
  • 1
  • 1
Constructor
  • 7,273
  • 2
  • 24
  • 66
  • 2
    See https://github.com/ldionne/hana (also http://stackoverflow.com/questions/25338795/is-there-a-name-for-this-tuple-creation-idiom) – Kerrek SB Aug 19 '14 at 11:35
  • 4
    You could ask the same of non-generic lambdas. – Simple Aug 19 '14 at 11:35
  • 3
    originally `lambda` is syntax sugar; For the easier >o – ikh Aug 19 '14 at 11:36
  • 4
    Your question suggests that syntactic sugar never brings any real improvement to a language. I strongly disagree with that. –  Aug 19 '14 at 11:37
  • @Simple I think I know an answer for non-generic-lambdas. They are exactly syntactic sugar, aren't them? – Constructor Aug 19 '14 at 11:38
  • @hvd OK, I agree with you, I used wrong words for my question. But what about second part of question? – Constructor Aug 19 '14 at 11:41
  • 2
    @Constructor The standard already requires the compiler to replace a lambda (generic or not) with an automatically generated class with a `operator()` member function. If the compiler can do it, I cannot think of any situation in which you cannot do it yourself. (But I've seen some very creative uses of lambdas in the recent past that allow things I wouldn't have thought possible, so I'm not entirely certain yet.) –  Aug 19 '14 at 11:49
  • 1
    Remember that lambdas can also capture local variables; so in general the equivalent hand-written class would also need data members and a constructor to initialise them. Since using a lambda avoids the error-prone duplication of declaring and initialising the members, I'd say it's rather more than just sugar. – Mike Seymour Aug 19 '14 at 11:53
  • @hvd But generic lambda should be replaced with a class template or a class with a templated member, shouldn't it? So there is a difference in behavior of the compiler when it deals with a simple lambda and generic one... – Constructor Aug 19 '14 at 11:57
  • @MikeSeymour I completely agree that lambdas are more than a simple syntatic sugar, I've incorrectly asked my question. In fact I'm really interested in the second part of it. – Constructor Aug 19 '14 at 11:59

3 Answers3

3

For the non-generic lambda expressions of C++11, there is a somewhat straightforward translation that can be performed:

void foo()
{
    int i = 42; int j = 22;
    auto f = [i, &j](int k) { return i + j + k };
    // proceed to use f
 }

For instance:

void foo()
{
    int i = 42; int j = 22;
    struct {
        int i; int& j;
        // can't deduce return type
        int operator()(int k) const
        { return i + j + k; }
    } f { i, j };
    // proceed to use f
}

For the generic lambda expressions of C++14, it’s not so straightforward. Suppose this time we’re using auto f = [i, &j](auto k) { return i + j + k; }. Then we must produce the following call operator:

template<typename T>
auto operator()(T k) const { return i + j + k; }

The problem is that we cannot define a template at function scope (a restriction also known as no local templates). So we must move out the closure type definition out of the enclosing function to namespace scope (giving it a name in the process), then use closure_type f { i, j };. Incidentally this means we have to give the class and its operator some form of linkage, whereas function local definitions have no linkage.

So in a sense, generic lambda expressions give us a limited version of local function templates.

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Thank you very much! Do you think that there are no other differences between a generic lambda and a closure class with templated `operator()`? – Constructor Aug 19 '14 at 12:40
  • 1
    @Constructor A closure type (produced from a lambda expression) is required to behave like such a class. This effectively means that things like `auto f = [] {}; auto ptm = &decltype(f)::operator();` are required to work — nothing has changed in that regard. – Luc Danton Aug 19 '14 at 12:46
  • Hmm, [it works even for generic lambda](http://coliru.stacked-crooked.com/a/d24edc083610e092). But how? – Constructor Aug 19 '14 at 12:51
  • Oh, it doesn't work, of course (I meant my code). *coliru* works a bit strange today. Yes, I know about this trick, thank you. – Constructor Aug 19 '14 at 13:07
1

On Lambdas in general:

Some consider this "really neat!"; others see it as a way to write dangerously obscure code. IMO, both are right. --- Bjarne Stroustrup

I think it is a question of how you use lambda. As small local closure function, that you use to improve handling with functions, which take function objects as parameters (like std::sort), I haven't actually seen an example, where generic lambdas would add any benefit.

If you use them to code haskell-like in C++, then it will add some benefit, but I have seen too many examples of code, where object lifetime was at least partially ignored. So I don't think, that it will add a benefit.

Let me explain that a bit:

void foo(std::vector<int>& v)
{
    std::sort(v.begin(), v.end(), [](int i, int j) { return (i < j); });
}

This is a real improvement, but registering a callback, that will be called later and possibly in another thread:

void C::foo()
{
    registerLazyMultithreadedCallback([=this]() { return this; });
}

This will make things complicated, because you have to ensure, that the object you return is valid. This could lead into ridiculous situations (e.g. calling short time after destruction). My experience is, that the coder will think twice before writing such a construct without lambda.

So if you use them only locally as helper functions, there is no need for generics, because all types are clear.

I guess I am one of those, who think that you can write dangerous obscure code with lambda.

Stefan Weiser
  • 2,264
  • 16
  • 25
  • 2
    Your answer is about simple lambdas, not generic ones. – Constructor Aug 19 '14 at 12:18
  • It is about usage of lambdas. If you use it locally for helper functions, there is no need for generic programming, because the types are clear... – Stefan Weiser Aug 19 '14 at 12:24
  • Plus, what you complain about is equally applicable to manually coded functions or functors, so lambdas aren't to blame for any of that. In situations where they are used correctly, they work correctly (i.e. the same) and look much more readable. You can write dangerous obscure code without lambdas, and it'll take up twice as many lines if you do. – underscore_d May 11 '17 at 09:58
0

Do C++14 generic lambdas bring a real improvement to the language

Yes.

or they are a kind of syntactic sugar?

Yes.

You seem to imply that syntactic sugar is not a real improvement to the language. Keep in mind that the language itself is syntactic sugar. You could be writing everything in machine code :)

tenfour
  • 36,141
  • 15
  • 83
  • 142
  • No, no. I agree that they is a real improvement. I used wrong words. But what about second part of question? – Constructor Aug 19 '14 at 11:44
  • It is not the syntactic sugar, that makes problems, but the developer, that can't handle things like object lifetime and scopes correctly. Lambda in general disguise those topics a bit, because of the capture. – Stefan Weiser Aug 19 '14 at 11:52