在通用lambda中使用template参数

use*_*483 6 c++ lambda c++14 c++20

GCC允许以下语法作为扩展:

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

n3418,2012年关于通用 lambdas的提议中,我们看到允许上述语法的语法:

overload( []<class T>(T* p) {...},
Run Code Online (Sandbox Code Playgroud)

但是,由于它是一个扩展,语法显然不存在(或者不被允许).当我们有auto时,上述什么情况会有用,为什么语法不存在(或不允许)?

pep*_*ico 8

在我看来,C++ 14的多态lambda只是更简洁.

您可以重现样本情况的效果,如下所示:

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
}
Run Code Online (Sandbox Code Playgroud)

虽然有很多情况下GCC扩展能力更强,但不仅仅是你的用例(它更适合自然).例如,关于非类型模板参数:

#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>{});    
}
Run Code Online (Sandbox Code Playgroud)

Coliru

复杂的通用参数类型:

void foo() {}

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

    accept_no_args_fun_only(foo);
}
Run Code Online (Sandbox Code Playgroud)

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});
}
Run Code Online (Sandbox Code Playgroud)

Coliru

我不讨论涉及包含泛型lambda的讨论,但我可以看到一个思考这种扩展是否值得包括当前语法涵盖大多数用例时,是否简洁,并且适合lambdas的意图,这通常用于生成简短的代码片段.

编辑

GCC扩展已经决定在第一次C++ 20 ISO标准会议上成为C++的一部分:

  • 所以将[此代码](http://coliru.stacked-crooked.com/a/48ad92e855f4fddc)翻译成*更灵活的lambdas* (2认同)