当 C++14 已经有了泛型 lambda 时,C++20 中引入的模板 lambda 有什么用?

What is the need of template lambda introduced in C++20 when C++14 already has generic lambda?

引入了通用的 lambda,可以编写以下内容:

auto func = [](auto a, auto b){
    return a + b;
};
auto Foo = func(2, 5);
auto Bar = func("hello", "world");

很明显,这个通用 lambda func 就像模板函数 func 一样工作。

为什么 C++ 委员会决定为通用 lamda 添加模板语法?

由于您可以在 C++20 中使用模板化 lambda,因此您可以使用比 SFINAE 表达式更简单的方式来限制您的类型:

auto lambda = []<typename T>(std::vector<T> t){};

此 lambda 仅适用于向量类型。

被 C++20 接受的 proposal 有一个冗长的动机部分,并带有示例。它的前提是这样的:

There are a few key reasons why the current syntax for defining generic lambdas is deemed insufficient by the author. The gist of it is that some things that can be done easily with normal function templates require significant hoop jumping to be done with generic lambdas, or can’t be done at all.The author thinks that lambdas are valuable enough that C++ should support them just as well as normal function templates.

下面是很多例子。

C++14 通用 lambda 是一种非常酷的方法来生成具有如下所示 operator () 的仿函数:

template <class T, class U>
auto operator()(T t, U u) const;

但不是这样的:

template <class T>
auto operator()(T t1, T t2) const; // Same type please

也不是这样的:

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please

也不是这样(尽管实际使用起来有点棘手):

template <class T>
auto operator()() const; // No deduction

C++14 lambda 很好,但 C++20 允许我们毫不费力地实现这些情况。

The new "familiar template syntax" for lambdas introduced in C++20 makes constructs such as for_types and for_range viable and way more readable compared to C++17 alternatives.

(来源:compile-time iteration with C++20 lambdas

另一件可以在 C++14 和 C++17 泛型 lambda 上完成的有趣事情是通过显式传递模板参数直接调用 operator()C++14:

auto l = [](auto){ };
l.template operator()<int>(0);

C++20(另见<tparams>on cppreference的解释):

auto l = []<typename T>(){ };
l.template operator()<int>();

上面的 C++14 示例非常无用:如果不给参数命名并使用 decltype,就无法在 lambda 主体中引用提供给 operator() 的类型.此外,我们被迫传递一个参数,即使我们可能不需要它。

C++20 示例展示了如何在 lambda 主体中轻松访问 T,以及现在可以任意模板化 nullary lambda。这对于上述编译时结构的实现非常有用。