如何创建可变参数泛型 lambda?
Posted
技术标签:
【中文标题】如何创建可变参数泛型 lambda?【英文标题】:How to create a variadic generic lambda? 【发布时间】:2014-11-11 05:07:42 【问题描述】:从 C++14 开始,我们可以使用泛型 lambda:
auto generic_lambda = [] (auto param) ;
这基本上意味着它的调用运算符是基于标记为自动的参数模板化的。
问题是如何创建一个可以接受可变参数数量的 lambda,类似于可变参数函数模板的工作方式?如果这是不可能的,那么可以以相同方式使用的最接近的东西是什么?
你将如何存储它? std::function
有可能吗?
【问题讨论】:
[](auto... params)
... ?
@Xeo 不错!你将如何使用它?您可以将其存储在 std::function 中吗?
不,因为std::function
的调用签名并非必然是多态的。
使用示例:weird lambda
@GingerPlusPlus GCC 4.9 and Clang 3.5
【参考方案1】:
我不确定您的意图是什么,但您可以使用 lambda 本身来捕获参数,而不是将其存储在 std::function
中。
这是在 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"));
【讨论】:
【参考方案2】:语法
如何创建可变参数泛型 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);
存储
如何存储可变参数泛型 lambda?
您可以使用 auto
将 lambda 存储在其自己类型的变量中,也可以将其存储在 std::function
中,但您只能使用您给该 @ 的固定签名来调用它987654335@:
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 的通常同质容器中。使用非泛型 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
查看this question 了解异构容器的示例。
还有什么?
有关 lambda 的更多一般信息以及有关生成的成员以及如何在 lambda 中使用参数的详细信息,请参阅:
http://en.cppreference.com/w/cpp/language/lambda How does generic lambda work in C++14? How to call a function on all variadic template args? What is the easiest way to print a variadic parameter pack using std::ostream?【讨论】:
@MikhailBasically you just add ... between auto (possibly ref qualified) and your parameter pack name.
因此,通常在具有通用引用参数包的情况下,您将拥有[](auto&&... params)
。不确定是否值得将此特定示例添加到帖子中。
这就是我在找到您的帖子时所寻找的。也许,我不是唯一一个。谢谢。
能否请您展示一个在 lambda 中使用参数的示例 - 您在此处编写的许多示例,但没有人给出完整示例
@serup 您使用参数的方式与使用模板参数包的方式相同,其他问题(***.com/q/17339789/1147772)涵盖了这一点,我会将链接添加到what else
部分
@Drax,此示例不显示 lambda 函数,仅显示模板函数【参考方案3】:
考虑一下
#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__)(" !");
(wandbox here) 这个“打印” lambda 是:
可变参数 递归 通用 快速而且看不到模板。 (就在下面 :) )没有看起来像无线电噪音的 C++ 代码。简单、干净,最重要的是:
易于维护难怪“感觉就像一门新语言”。
【讨论】:
为了不混淆答案,我故意只说“快”。它实际上非常快。因为它几乎是一个编译时代码。因此,if-constexpr 优化是可能的。 这也是为什么我没有使用正确的签名auto print = [](auto && first_param, auto && ... params)
它在魔杖盒示例中答案中提供
@Nikos,我不明白你为什么认为它不是递归的? “打印” lambda 调用自身。这是编译时递归的,任何好的编译器都会将其转换为非递归的以供运行时使用。是这个意思吗?
嗨@Elliot,“Nikos”是谁?
@ChefGladiator 老实说我不记得这段对话了,但我猜一些“Nikos”删除了他们的评论......以上是关于如何创建可变参数泛型 lambda?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以解决“为可变参数参数创建 T 的通用数组”编译器警告?
Kotlin泛型 ② ( 可变参数 vararg 关键字与泛型结合使用 | 使用 [] 运算符获取指定可变参数对象 )