为什么我不能在C ++ 11中创建Lambda向量(相同类型)?


88

我试图创建一个lambda向量,但是失败了:

auto ignore = [&]() { return 10; };  //1
std::vector<decltype(ignore)> v;     //2
v.push_back([&]() { return 100; });  //3

直到第2行,它编译正常。但是第3行给出了编译错误

错误:没有匹配的函数调用'std :: vector <main():: <lambda()>> :: push_back(main():: <lambda()>)'

我不需要函数指针的向量或函数对象的向量。但是,封装真正的lambda表达式的功能对象的矢量对我有用。这可能吗?


23
“我不需要函数指针的向量或函数对象的向量。” 但这就是您要的。Lambda一个函数对象。
Nicol Bolas

Answers:


135

每个lambda都有不同的类型-即使它们具有相同的签名。您必须使用运行时封装容器,例如,std::function如果您想做类似的事情。

例如:

std::vector<std::function<int()>> functors;
functors.push_back([&] { return 100; });
functors.push_back([&] { return  10; });

52
管理一百人的开发团队听起来对我来说就像一场噩梦:)
杰里米·弗里斯纳

10
另外,请不要忘记,无捕获的lambda([]样式)可以降级为函数指针。因此,他可以存储相同类型的函数指针数组。请注意,VC10尚未实现。
Nicol Bolas

顺便说一句,在这些示例中是否也应该使用较少捕获功能?还是有必要?-顺便说一句,VC11似乎支持无捕获Lambda到函数指针。没测试。
Klaim 2011年

2
是否可以创建向量存储不同类型的函数?即不是将其限制为std::function<int(),我可以使用其他函数原型吗?
manatttta

2
@manatttta有什么意义?存在容器来存储相同类型的对象,以一起组织和操纵它们。您可能还会问:“我可以vector同时创建一个存储std::functionstd::string吗?” 答案是相同的:不,因为那不是预期的用途。您可以使用“变体”风格的类来执行足够的类型擦除,以将不同的东西放入容器中,同时包括一种供用户确定“真实”类型并因此选择处理方式的方法(例如,如何调用)每个元素...但是同样,为什么要那么长?有什么真正的理由吗?
underscore_d

40

所有的lambda表达式都有不同的类型,即使它们的每个字符都相同。您正在将另一种类型的lambda(因为它是另一个表达式)推入向量,这显然不起作用。

一种解决方案std::function<int()>代替它。

auto ignore = [&]() { return 10; };
std::vector<std::function<int()>> v;
v.push_back(ignore);
v.push_back([&]() { return 100; });

另一方面,[&]当您不捕获任何东西时,使用它不是一个好主意。


14
不需要()没有参数的lambda。
小狗

18

尽管其他人说的话很相关,但仍然可以声明和使用lambda向量,尽管它不是很有用:

auto lambda = [] { return 10; };
std::vector<decltype(lambda)> vec;
vec.push_back(lambda);

因此,您可以在其中存储任意数量的lambda,只要它是/的副本/移动即可lambda


如果回推发生在具有不同参数的循环中,这实际上可能很有用。大概是出于懒惰评估的目的。
MaHuJa 2011年

7
不,您不将参数放在矢量中,仅将函数对象放在矢量中。因此,它将是带有相同lambda的所有副本的矢量
hariseldon78 2012年

16

如果您的lambda是无状态的,即[](...){...}C ++ 11允许它降级为函数指针。从理论上讲,符合C ++ 11的编译器将能够编译此代码:

auto ignore = []() { return 10; };  //1 note misssing & in []!
std::vector<int (*)()> v;     //2
v.push_back([]() { return 100; });  //3

4
备案auto ignore = *[] { return 10; };将使ignore一个int(*)()
卢丹顿

1
@Luc,哦,太可恶了!他们何时添加的?
MSN

3
好吧,因为首先要允许允许使用函数指针的转换函数不是explicit,所以取消引用lambda表达式是有效的,并且取消引用由转换产生的指针。然后使用auto将参考返回给指针的衰减。(使用auto&auto&&将保留引用。)
Luc Danton

啊...取消引用结果指针。那讲得通。丢失是()故意的还是偶然的?
MSN

故意地,lambda表达式是等效的(但要短两个字符)。
Luc Danton

6

您可以使用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);进行不必要的调用,如果我们编写this可以避免decltype(lambda_gen(1))
纳瓦兹

那还不打个电话吗?还有一点要注意的是,该问题指出了C ++ 11,因此需要在我认为的函数中添加尾随返回类型。
antediluvian

号里面什么decltype未计算的,因此呼叫实际上没有做。情况sizeof也是一样。另外,即使您添加尾随返回类型,此代码也无法在C ++ 11中使用!
纳瓦兹

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.