8

GCC allows the following syntax as an extension:

// a functional object that will add two like-type objects
auto add = [] <typename T> (T a, T b) { return a + b; };

In n3418, the 2012 proposal for generic lambdas, we see syntax that allows the above:

overload( []<class T>(T* p) {...},

However, since it is an extension the syntax is clearly absent (or not allowed.) In what situations would the above be useful when we have auto, and why is the syntax absent (or not allowed)?

oblitum
  • 11,380
  • 6
  • 54
  • 120
user4155483
  • 81
  • 1
  • 2

1 Answers1

10

It seems to me that C++14's polymorphic lambdas are just more terse.

You can reproduce the effect of your sample situation like the following:

struct A {};
struct B {};

int operator+(A, A) { return 1; }
int operator+(B, B) { return 2; }
int operator+(A, B) { return 3; }
int operator+(B, A) { return 4; }

int main() {
    auto add = [](auto a, decltype(a) b) { return a + b; };
    auto flexible_add = [](auto a, auto b) { return a + b; };

    add(A{}, A{});  // works
    add(B{}, B{});  // works
    add(A{}, B{});  // doesn't work

    flexible_add(A{}, A{});  // works
    flexible_add(B{}, B{});  // works
    flexible_add(A{}, B{});  // works

    auto deref = [](auto *a) { return *a; };
    int foo{};
    A a;
    B b;
    deref(&foo); // works
    deref(&a);   // works
    deref(&b);   // works
    deref(foo);  // doesn't work
    deref(a);    // doesn't work
    deref(b);    // doesn't work
}

Though there are many cases where the GCC extension is more capable, not only on your use case (where it fits more naturally). For example, regarding non-type template parameters:

#include <cstddef>
#include <utility>
#include <iostream>

void print(std::initializer_list<std::size_t> il)
{
    for (auto&& elem : il) std::cout << elem << std::endl;
}

int main()
{
    auto indexed_lambda = [] <std::size_t... Is> (std::index_sequence<Is...>) { print({Is...}); };

    indexed_lambda(std::make_index_sequence<5>{});    
}

Coliru

Complex generic parameter types:

void foo() {}

int main() {
    auto accept_no_args_fun_only = [] <typename R> (R (*)()) {};

    accept_no_args_fun_only(foo);
}

Coliru

Variadics:

#include <tuple>
#include <vector>

int main() {
    auto accept_vector = [] (std::vector<auto> &&) {}; // Unconstrained placeholder from Concept TS, but not variadic
    auto accept_tuple = [] <typename... Args> (std::tuple<Args...> &&) {};

    accept_vector(std::vector{42});
    accept_tuple(std::tuple{42});
}

Coliru

I dunno the discussion involving inclusion of generic lambdas, but I can see one pondering whether such extension is worth including when the current syntax covers the majority of use cases, is terse, and appropriate for the intent of lambdas, which most often is for producing short snippets of code.

EDIT

The GCC extension has been decided to become part of C++ on the first C++20 ISO standards meeting:

oblitum
  • 11,380
  • 6
  • 54
  • 120
  • 2
    so translate [this code](http://coliru.stacked-crooked.com/a/48ad92e855f4fddc) to your *more flexible lambdas* – Piotr Skotnicki Oct 19 '14 at 20:15
  • I just wanted to point out that there are cases which generic lambda does not support – Piotr Skotnicki Oct 19 '14 at 21:03
  • I don't think your example is related to variadic templates, but rather to non-type template parameters. – Nir Friedman Jul 16 '17 at 02:38
  • @NirFriedman I simply don't get your point. non-type template parameters and variadic templates are not mutually exclusive, and the sample employs both. Notice that I'm not the original author of the ending sample, it was copied verbatim from Piotr's suggestion, which I've embedded as I do see the relevance. – oblitum Jul 16 '17 at 03:10
  • @pepper_chico Yes, the example is both variadic, and non-type, but the `auto` syntax has zero problem with the former, and cannot express the latter. So the statement that gcc is more capable with regards to "variadic template parameters" is incorrect, and the example is misleading. gcc is more capable with regards to non-type parameters, that is all, and an example with a single integer template parameter would demonstrate that. – Nir Friedman Jul 16 '17 at 03:30
  • @NirFriedman How would you express this with C++14 generic lambdas http://coliru.stacked-crooked.com/a/0d472d7a59d3cdfc? I mean, at the prototype. – oblitum Jul 16 '17 at 04:36
  • @pepper_chico Again, you are mixing in something totally unrelated. How would you do `[] (void (*)(Arg))` with the C++14 generic lambda syntax? The issue in your example is again not variadics, but the inability to handle templates that appear in a deduced context outside of certain specific cases (mostly, cv, ref, pointer, or array qualifications). – Nir Friedman Jul 16 '17 at 13:17
  • @NirFriedman OK, so we have already augmented from not being able to tackle _just_ non-type template parameter, to include those cases as well. Agreed, again, non mutually exclusive features. On your final remarks: "mostly" only that? I see it as pervasive, e.g. http://coliru.stacked-crooked.com/a/b1b4c33f1f0b024f. Notice that this time I've put a non-variadic version besides, that compiles due to Concepts TS, which doesn't cover the variadic version. The latter doesn't require the Concepts feature while it **also** covers variadic templates. So, on this one, is it more variadic capable? – oblitum Jul 16 '17 at 17:01
  • @pepper_chico Sure in that case it is more variadically capable, because you can write e.g. `tuple` but not `tuple`, that is clear. But this is C++17 + Concepts. The original question was about 14 (for some reason, you added the 20 tag). In 14, `tuple` is not legal either. So again, the difference in capability is totally unrelated to variadics. So the statement that gcc is more capable with regards to variadics remains incorrect, and the example remains misleading. gcc is more capable with regards to the types of allowed deductions. – Nir Friedman Jul 16 '17 at 17:30
  • @NirFriedman Let's not conflate capability of a language feature with a compiler specific capability. On the language side, this has been added to C++20, isn't it clear in the answer edit? Which makes the information discussed here relevant for that tag as well. On the compiler side, it _was/is_ a GCC extension but is now set for the standard. My previous question of course wasn't limited to 14. – oblitum Jul 16 '17 at 17:45
  • 1
    @NirFriedman I've added a final edit rewording the answer a whole to embedded the information and samples in this discussion. Hope it's not misinforming anymore. – oblitum Jul 16 '17 at 18:19