如何创建可变参数泛型 lambda
How to create a variadic generic lambda?
从 C++14 开始,我们可以使用通用 lambdas:
auto generic_lambda = [] (auto param) {};
这基本上意味着它的调用运算符是基于标记为 auto 的参数进行模板化的。
问题是如何创建一个可以接受可变参数数的lambda,类似于可变参数函数模板的工作方式?如果这是不可能的,那么可以以同样方式使用的最接近的东西是什么?你会如何存储它?在std::function
中可能吗?
我不确定您的意图是什么,但您可以使用lambda本身来捕获参数,而不是将其存储在std::function
中。这是在提升邮件列表中讨论的一个例子。它用于 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"));
语法
你如何创建一个可变参数泛型 lambda?
您可以使用以下语法创建可变参数泛型 lambda:
auto variadic_generic_lambda = [] (auto... param) {};
基本上,您只需在auto
(可能符合 ref 条件(和参数包名称之间添加...
。
因此,通常使用通用引用会给出:
auto variadic_generic_lambda = [] (auto&&... param) {};
用法
你如何使用参数?
您应该将可变参数泛型参数视为具有模板参数包类型,因为确实如此。这或多或少意味着这些参数的大多数(如果不是全部(用法都需要模板。
下面是一个典型的例子:
#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);
}
存储
你如何存储可变参数通用λ?
您可以使用 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 都有不同的类型,因此不能将它们的直接类型存储在 STL 的常用同类容器中。使用非通用 lambda 的方法是将它们存储在相应的std::function
中,该将具有固定的签名调用,并且不会限制任何东西,因为您的 lambda 首先不是通用的,只能以这种方式调用:
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>
-
std::vector<boost::any>
-
boost::fusion::vector
有关异构容器的示例,请参阅此问题。
还有什么?
有关 lambda 的更多常规信息,以及有关生成的成员以及如何在 lambda 中使用参数的详细信息,请参阅:
- http://en.cppreference.com/w/cpp/language/lambda
- 通用 lambda 在 C++14 中如何工作?
- 如何在所有可变参数模板参数上调用函数?
- 使用 std::ostream 打印可变参数包的最简单方法是什么?
考虑一下
#include <iostream>
namespace {
auto out_ = [] ( const auto & val_)
{
std::cout << val_;
return out_ ;
};
auto print = [](auto first_param, auto... params)
{
out_(first_param);
// if there are more params
if constexpr (sizeof...(params) > 0) {
// recurse
print(params...);
}
return print;
};
}
int main()
{
print("Hello ")("from ")("GCC ")(__VERSION__)(" !");
}
(魔杖在这里(这个"打印"λ是:
- 可变参数
- 递归的
- 通用
- 快
而且看不到模板。(就在:)下面(没有看起来像无线电噪声的C++代码。简单,干净,最重要的是:
- 易于维护
难怪"感觉像一门新语言"。
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 如何使用可变参数模板强制转换每个变体类型
- 关于如何在具有单个参数的变体构造中选择替代方案?
- 调用参数排列不变函数 f(i++, i++)
- 参数归纳与标准::变体
- 模板化回调参数的逆变,如 C# 中的逆变
- 如何在没有参数包的情况下编写变差函数
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 获取模板参数的成员变量值列表
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- 如何定义变体<x,y,z>提取模板参数的子类型
- 正确对齐内存模板,参数顺序不变
- 递归中不同参数类型的变元模板函数
- 通过函数指针传递给变差函数的参数会更改其值
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 使用可变参数模板参数提升变体访问者
- boost ::变体 - 为什么模板参数比const字符串参数具有更高的优先级
- 将变参数包中的值加载到临时数组中
- 使用额外参数提升变体访客
- 从变长参数列表中提取std::string