我正在学习c ++ 11中的新功能并遇到了这个问题。我想通过在lambda中移动它作为for_each的参数来捕获unique_ptr。
设置:
std::array<int,4> arr = {1,3,5,6};
std::unique_ptr<int> p(new int); (*p) = 3;
尝试1 - 不起作用,因为unique_ptr没有复制构造函数。 c ++ 0x没有指定移动语法的传递。
std::for_each(arr.begin(), arr.end(), [p](int& i) { i+=*p; });
尝试2 - 使用bind将p的移动副本绑定到一个带有int&amp;:
的函数std::for_each(arr.begin(), arr.end(),
std::bind([](const unique_ptr<int>& p, int& i){
i += (*p);
}, std::move(p))
);
编译器抱怨'result' : symbol is neither a class template nor a function template.
练习的主要目的是了解如何在lambda中捕获可移动变量,以便以后使用。
答案 0 :(得分:18)
更新:您可以从C ++ 14开始捕获lambda中的可移动变量。
std::for_each(arr.begin(), arr.end(), [p=std::move(p)](int& i) { i+=*p; });
在C ++ 11中,你无法以任何直接的方式将可移动变量捕获到lambda中。
通过复制或引用捕获Lambda。因此,要捕获仅移动变量,您必须将其包装在一个对象中,其中复制=&gt;移动(例如std::auto_ptr
)。这是一个讨厌的黑客。
在您的示例中,您可以通过引用捕获,但如果这只是简化代码,则可能无法使用实际代码执行您想要的操作:
std::for_each(arr.begin(), arr.end(), [&p](int& i) { i+=*p; });
这是一个仅复制移动的包装器:
template<typename T>
struct move_on_copy_wrapper
{
mutable T value;
move_on_copy_wrapper(T&& t):
value(std::move(t))
{}
move_on_copy_wrapper(move_on_copy_wrapper const& other):
value(std::move(other.value))
{}
move_on_copy_wrapper(move_on_copy_wrapper&& other):
value(std::move(other.value))
{}
move_on_copy_wrapper& operator=(move_on_copy_wrapper const& other)
{
value=std::move(other.value);
return *this;
}
move_on_copy_wrapper& operator=(move_on_copy_wrapper&& other)
{
value=std::move(other.value);
return *this;
}
};
然后您可以像这样使用它:
int main()
{
std::unique_ptr<int> p(new int(3));
move_on_copy_wrapper<std::unique_ptr<int>> mp(std::move(p));
[mp]()
{
std::cout<<"*mp.value="<<*mp.value<<std::endl;
}
();
std::cout<<"p="<<p.get()<<", mp="<<mp.value.get()<<std::endl;
}
答案 1 :(得分:3)
你的尝试2几乎可以运作。
缺少的是您没有告诉bind
来电预期参数:
std::for_each(arr.begin(), arr.end(),
std::bind([](const unique_ptr<int>& p, int& i){
i += (*p);
}, std::move(p), std::placeholders::_1)
);
placeholders::_1
必须告诉bind
的结果,它应该期望为其operator()
传递给它的参数。
这也是@ marton78的回答here中给出的建议。