C++ &引用;刷新“;lambda对象
我创建了我的lambda,如下所示:C++ &引用;刷新“;lambda对象,c++,c++11,lambda,C++,C++11,Lambda,我创建了我的lambda,如下所示: int i = 0; auto gen_lam = [=]() mutable -> int {return ++i;}; 它有效地统计调用它的次数,因为它存储捕获的i。有没有办法“重建”对象,使其从初始值i开始 大致如下: decltype(gen_lam) gen_lam2; 这样,以下代码输出的是11,而不是12 std::cout << gen_lam() << std::endl; decltype(gen_la
int i = 0;
auto gen_lam = [=]() mutable -> int {return ++i;};
它有效地统计调用它的次数,因为它存储捕获的i
。有没有办法“重建”对象,使其从初始值i
开始
大致如下:
decltype(gen_lam) gen_lam2;
这样,以下代码输出的是11
,而不是12
std::cout << gen_lam() << std::endl;
decltype(gen_lam) gen_lam2;
std::cout << gen_lam2() << std::endl;
std::cout简单地完成,将lambda创建封装在lambda中,您可以在需要重新初始化内部lambda时调用该lambda:
auto wrap_lam = [](int i) {return [=]() mutable {return ++i;};}
auto gen_lam = wrap_lam(0);
auto gen_lam2 = wrap_lam(0);
或者,只要在需要时复制以保留状态:
auto gen_lam = [=]() mutable -> int {return ++i;};
const auto save = gen_lam;
如果您只需要完全重置,那么首先自然保存为const对象。我不认为lambda捕获的初始值可以是其类型的一部分,因为这意味着每次代码运行时(可能使用不同的I
)都必须在运行时生成一个新类型
我也不认为捕获的可变值的初始状态是存储的,因为这会占用额外的内存
总之,如果你只有一个lambda函数对象,它是按照你描述的方式创建的,我认为你没有任何方法可以重新创建它的原始状态
但是,如果您控制生成该函数对象的代码,则可以将其拉入函数,然后再次调用该函数。或者你可以手工创建一个函数对象类,正如@NeilKirk已经建议的那样。我认为你想要的可以通过一个捕获不同计数器的生成器来实现
#include <iostream>
#include <functional>
using namespace std;
int main()
{
int i = 0;
int j = 0;
auto lambda_generator = [](int& val) {
auto var = [=]() mutable -> int {return ++val;};
return var;
};
auto counter1 = lambda_generator(i);
std::cout << counter1() << std::endl;
auto counter2 = lambda_generator(j);
std::cout << counter2() << std::endl;
}
#包括
#包括
使用名称空间std;
int main()
{
int i=0;
int j=0;
自动lambda_生成器=[](int&val){
自动变量=[=]()可变->int{return++val;};
收益var;
};
自动计数器1=lambda_发电机(i);
std::cout不能访问lambda内部复制的内部变量,但lambda本身可以
通过在调用上建立协议,您可以向lambda发送命令以改变其状态。例如:
auto counter = [](int i0){
int i = i0;
return [i0, i](bool reset=false) mutable {
if (reset) {
i = i0;
return -1;
} else {
return ++i;
}
};
};
这里我使用了一个可选参数,当传递true
时,它会将计数器重置为初始值
int main() {
auto c = counter(10);
std::cout << c() << "\n"; // 11
std::cout << c() << "\n"; // 12
std::cout << c() << "\n"; // 13
c(true); // send reset message
std::cout << c() << "\n"; // 11
std::cout << c() << "\n"; // 12
std::cout << c() << "\n"; // 13
}
intmain(){
自动c=计数器(10);
std::cout为了简单和理智,我会为此创建一个普通的旧函子类。你可以在std::function
@402:这没有异议。你也不能从匿名名称空间命名类型。@402:啊,我理解你的错误。你不能decltype([]{})lambda=[]{}因为这两个lambda具有不同的类型。不能命名这些类型的事实是不相关的。对于decltype(1)foo=“one”,您有相同的两种类型问题;
@402第二个示例的共享状态让我很害怕。重复数据消除器的解决方案是每个lambda都有自己的状态,这要好得多。@SebastianRedl我同意……我甚至没有想过捕获复制的传递值整数。出于教学目的,我会在这里留下我蹩脚的答案。@MSalters我会完全删除第二个示例n甚至写auto const prototype=[=]()可变{return++i;}
所以您知道原型本身并没有意外地增加。很好……我甚至没有想到在生成器中捕获传递值计数器。@MSalters:只是想指出,它可以在任何时候保存,而不仅仅是在创建时。当然,如果只需要完全重置,您的最好是在逻辑错误-编译器会抱怨的语法错误。谢谢,复制似乎是解决我的问题的最好办法。@MSalters使用const
非常好的主意。请尝试!捕获的变量的初始值不需要存储,因为原始i
是通过值捕获的,因此不需要“接触”是的,但原始的i
可能早已超出范围。在您的问题中,您不太清楚为什么要刷新/重置lambda对象,因此我尝试以最小的假设逐字解决问题-仅给定lambda对象,尝试重置它或进行“刷新”复制。在您的代码中,将有两个版本的i
:一个是局部变量(始终保持不变),其中一个是lambda中的值copy。但是每次调用lambda时,该副本都会被修改,因此您必须返回原始的i
来获得起始值,您不能仅通过查看lambda对象本身来获得它。我明白您现在的意思。但在我看来,重建lambda对象d类似于实例化一个函子的类,从而“重新捕获”最初使用的i
。这就是为什么我尝试decltype(gen_lam)
作为(如愿以偿的)手段来获取对象的类型