假设使用lambda函数时,假设您决定复制变量(使用[=]表示法)。如果您再也没有引用该变量,是否允许编译器将其移动到结果函数对象中?
编辑:例如,我编写了一个代码段来跨线程移动调用。这是一个这样做的示例。
extern "C" __declspec(dllexport) void parser_file_updated(Parser* p, const char* filename, int offset, int added) {
std::string file(filename);
p->make_call([=]() {
p->file_updated(std::move(file), offset, added);
});
}
但很明显,文件变量不需要超出lambda定义-实际上,lambda仅被调用一次,因此我移动了副本。
最佳答案
否。唯一允许编译器用移动替换副本的情况是完全相同的情况,它允许执行复制省略。这些情况包括按值返回本地对象或使用临时对象初始化对象。在这些情况下,允许编译器通过使源和目标成为同一对象来删除副本。如果编译器由于某种原因无法执行此操作,则必须将源对象视为重载解析的右值,以便为目标对象选择适当的构造函数。但是,在您的情况下,文件是左值,并且上述情况均不适用。您将必须使用显式移动。
不幸的是,C++ 11没有“移动捕获”的语法。恕我直言,真是可惜。但是std::bind支持这一点。应该可以将std::bind与一个lambda表达式结合起来,如下所示:
void foo(char const* p) {
string s = p;
auto fun = bind([](string const& s){
...
},move(s));
fun();
}
以便将字符串移到函数对象中。
如果您打算只调用一次此函数,并且想将字符串再次从函数对象中移出,则可以使用非常量引用:
void foo(char const* p) {
string s = p;
auto fun = bind([](string & s) {
some_other_func(move(s));
},move(s));
fun();
}
请注意,如果您不想在此处使用bind,而是让lambda对象的构造函数创建s的副本,则将字符串移出函数对象需要使用mutable关键字:
void foo(char const* p) {
string s = p;
auto fun = [=]() mutable {
// ^^^^^^^
some_other_func(move(s));
};
fun();
}
因为否则封闭类型的operator()函数将是const限定的,这又使
s
成为const限定的字符串。在C++ 14中,lambda capture子句变得更加灵活。我们现在可以写
void foo(char const* p) {
string s = p;
auto fun = [s=move(s)]() mutable { // #1
some_other_func(move(s)); // #2
};
fun();
}
其中#1将字符串值移到lambda对象中,而#2将字符串值移出(具体取决于
some_other_func
的声明方式)。关于c++ - 与lambdas一起移动,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4433109/