为啥我不能在 C++11 中创建一个 lambda 向量(相同类型)?
Posted
技术标签:
【中文标题】为啥我不能在 C++11 中创建一个 lambda 向量(相同类型)?【英文标题】:Why can't I create a vector of lambdas (of the same type) in C++11?为什么我不能在 C++11 中创建一个 lambda 向量(相同类型)? 【发布时间】:2011-11-20 14:18:09 【问题描述】:我试图创建一个 lambda 向量,但失败了:
auto ignore = [&]() return 10; ; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() return 100; ); //3
直到第 2 行,它是compiles fine。但是第 3 行给出了compilation error:
错误:没有匹配函数调用 'std::vector
>::push_back(main():: )'
我不想要函数指针向量或函数对象向量。但是,封装 real lambda 表达式的函数对象向量对我有用。这可能吗?
【问题讨论】:
“我不想要函数指针向量或函数对象向量。”但这就是你要求的。 lambda 是一个函数对象。 密切相关:What is the type of lambda when deduced with “auto” in C++11?. 【参考方案1】:每个 lambda 都有不同的类型——即使它们具有相同的签名。如果您想做类似的事情,您必须使用运行时封装容器,例如 std::function
。
例如:
std::vector<std::function<int()>> functors;
functors.push_back([&] return 100; );
functors.push_back([&] return 10; );
【讨论】:
管理一个一百人的开发团队对我来说更像是一场噩梦 :) 另外,不要忘记无捕获 lambda([] 样式)可以降级为函数指针。所以他可以存储一个相同类型的函数指针数组。请注意,VC10 还没有实现。 顺便说一句,在这些示例中不应该使用 capture-less 吗?还是有必要? - 顺便说一句,VC11 似乎支持函数指针的无捕获 lambda。不过没有测试。 是否可以创建不同类型的向量存储函数?即我可以使用不同的函数原型,而不是将其限制为std::function<int()
?
@manatttta 有什么意义?容器的存在是为了存储相同类型的对象,将它们组织和操作在一起。你不妨问'我可以创建一个vector
存储std::function
和std::string
吗?答案是一样的:不,因为那不是预期用途。您可以使用“变体”风格的类来执行足够的类型擦除以将不同的东西放入容器中,同时包括一种方法供用户确定“真实”类型并因此选择要做什么(例如如何调用)每个元素......但同样,为什么要这么长?有什么真正的理由吗?【参考方案2】:
所有 lambda 表达式都有不同的类型,即使它们逐个字符都相同。您将不同类型的 lambda(因为它是另一个表达式)推入向量中,这显然行不通。
One solution 是改为制作std::function<int()>
的向量。
auto ignore = [&]() return 10; ;
std::vector<std::function<int()>> v;
v.push_back(ignore);
v.push_back([&]() return 100; );
另一方面,当您没有捕获任何内容时,使用 [&]
并不是一个好主意。
【讨论】:
对于不带参数的 lambda,不需要()
。【参考方案3】:
虽然其他人说的很相关,但仍然可以声明和使用 lambda 向量,尽管它不是很有用:
auto lambda = [] return 10; ;
std::vector<decltype(lambda)> vec;
vec.push_back(lambda);
因此,您可以在其中存储任意数量的 lambda,只要它是 lambda
的副本/移动!
【讨论】:
如果推回发生在具有不同参数的循环中,这实际上可能很有用。大概是出于惰性评估的目的。 不,你没有把参数放在向量中,只是函数对象。所以它是一个向量,所有副本都具有相同的 lambda【参考方案4】:如果您的 lambda 是无状态的,即[](...)...
,C++11 允许它降级为函数指针。理论上,兼容 C++11 的编译器可以编译这个:
auto ignore = []() return 10; ; //1 note misssing & in []!
std::vector<int (*)()> v; //2
v.push_back([]() return 100; ); //3
【讨论】:
为了记录,auto ignore = *[] return 10; ;
将使ignore
成为int(*)()
。
@Luc,哦,太恶心了!他们什么时候添加的?
好吧,因为首先允许使用函数指针的转换函数被强制要求不是explicit
,所以取消引用 lambda 表达式是有效的,并且取消引用转换产生的指针。然后使用auto
将该引用衰减回指针。 (使用 auto&
或 auto&&
会保留引用。)
啊...取消引用结果指针。这就说得通了。丢失()
是有意还是无意?
有意的,lambda 表达式是等价的(但短了两个字符)。【参考方案5】:
您可以使用 lambda 生成函数(使用 Nawaz 建议的修复更新):
#include <vector>
#include <iostream>
int main()
auto lambda_gen = [] (int i) return [i](int x) return i*x;; ;
using my_lambda = decltype(lambda_gen(1));
std::vector<my_lambda> vec;
for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i));
int i = 0;
for (auto& lambda : vec)
std::cout << lambda(i) << std::endl;
i++;
但我认为此时您基本上已经创建了自己的课程。否则,如果 lambda 具有完全不同的 caputres/args 等,您可能必须使用元组。
【讨论】:
将它包装在像lambda_gen
这样的函数中的好主意,它本身又可以是一个 lambda。但是,auto a = lambda_gen(1);
进行了不必要的调用,如果我们编写此 decltype(lambda_gen(1))
,则可以避免这种情况。
那不是还要打额外电话吗?另一个小问题是问题说明了 C++11,所以我认为需要在函数中添加尾随返回类型。
没有。 decltype
中的任何内容都未评估,因此实际上并未进行调用。 sizeof
也是如此。此外,即使您添加尾随返回类型,此代码也无法在 C++11 中运行!!【参考方案6】:
每个 lambda 都是不同的类型。您必须使用std::tuple
而不是std::vector
。
【讨论】:
以上是关于为啥我不能在 C++11 中创建一个 lambda 向量(相同类型)?的主要内容,如果未能解决你的问题,请参考以下文章