Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using template parameter in a generic lambda

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)?

like image 603
user4155483 Avatar asked Oct 18 '14 00:10

user4155483


1 Answers

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:

  • http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0428r1.pdf
like image 103
pepper_chico Avatar answered Sep 23 '22 04:09

pepper_chico