如何创建一个可变的通用lambda?

问题描述 投票:34回答:3

从C ++ 14开始,我们可以使用泛型lambdas:

auto generic_lambda = [] (auto param) {};

这基本上意味着它的调用操作符基于标记为auto的参数进行模板化。

问题是如何创建一个可以接受可变参数数量的lambda,类似于可变参数函数模板的工作方式?如果这不可能,最接近的东西可以用同样的方法吗?你会怎么存储它?是否有可能在std::function

c++ lambda c++14 variadic
3个回答
38
投票

我不确定你的意图是什么,但不是将它存储在std::function中,你可以使用lambda本身捕获params。这是在boost邮件列表中讨论的示例。它用于boost::hana实现

auto list = [](auto ...xs) {
    return [=](auto access) { return access(xs...); };
};

auto head = [](auto xs) {
    return xs([](auto first, auto ...rest) { return first; });
};

auto tail = [](auto xs) {
    return xs([](auto first, auto ...rest) { return list(rest...); });
};

auto length = [](auto xs) {
    return xs([](auto ...z) { return sizeof...(z); });
};

// etc...
// then use it like

auto three = length(list(1, '2', "3")); 

29
投票

句法

你如何创建一个可变的通用lambda?

您可以使用以下语法创建可变参数通用lambda:

auto variadic_generic_lambda = [] (auto... param) {};

基本上你只需在...(可能是ref qualified)和你的参数包名称之间添加auto

所以通常使用通用引用会给出:

auto variadic_generic_lambda = [] (auto&&... param) {};

用法

你如何使用这些参数?

您应该将variadic泛型参数视为具有模板参数包类型,因为它就是这种情况。这或多或少意味着大多数(如果不是全部)这些参数的使用将需要模式以这种方式或另一种方式。

这是一个典型的例子:

#include <iostream>

void print(void)
{
}

template <typename First, typename ...Rest>
void print(const First& first, Rest&&... Args)
{
  std::cout << first << std::endl;
  print(Args...);
}

int     main(void)
{
  auto variadic_generic_lambda = [] (auto... param)
    {
      print(param...);
    };

  variadic_generic_lambda(42, "lol", 4.3);
}

存储

你如何存储一个可变的通用lambda?

你可以使用auto将lambda存储在它自己类型的变量中,或者你可以将它存储在std::function中,但是你只能使用你给std::function的固定签名来调用它:

auto variadic_generic_lambda = [] (auto... param) {};

std::function<void(int, int)> func = variadic_generic_lambda;

func(42, 42); // Compiles

func("lol"); // Doesn't compile

可变系列通用lambda的集合怎么样?

由于每个lambda具有不同的类型,因此您无法将其直接类型存储在STL的通常的同类容器中。使用非泛型lambdas的方法是将它们存储在相应的std::function中,该auto non_generic_lambda_1 = [] (int, char) {}; auto non_generic_lambda_2 = [] (int, char) {}; std::vector<std::function<void(int, char)>> vec; vec.push_back(non_generic_lambda_1); vec.push_back(non_generic_lambda_2); 将具有固定的签名调用,并且不会限制任何内容,因为您的lambda首先不是通用的,并且只能以这种方式调用:

std::vector<boost::variant>

如本存储部分的第一部分所述,如果您可以限制自己使用给定的固定调用签名,那么您可以对可变参数通用lambda执行相同的操作。

如果你不能,你将需要某种形式的异构容器,如:

有关异构容器的示例,请参阅http://en.cppreference.com/w/cpp/language/lambda

还有什么 ?

有关lambdas的更多常规信息以及有关生成的成员以及如何在lambda中使用参数的详细信息,请参阅:


2
投票

考虑一下

wandbox here

(qazxswpoi)这个“打印”lambda是:

  • 可变参数
  • 递归
  • 通用
  • 快速

看不到任何模板。 (就在下面:))没有看起来像无线电噪音的C ++代码。简单,干净,最重要的是:

  • 易于维护

难怪“感觉就像一种新语言”。

© www.soinside.com 2019 - 2024. All rights reserved.