在std :: unique_ptr中使用lambda中的std :: bind

时间:2017-03-02 02:41:39

标签: c++ c++11 visual-studio-2015 lambda

// By const l-value reference
auto func2 = std::bind([](const std::unique_ptr< std::vector<int> >& pw) // fine
{
    std::cout << "size of vector2: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));

//By non-const l-value reference
auto func3 = std::bind([](std::unique_ptr< std::vector<int> >& pw) // fine
{
    std::cout << "size of vector3: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));

// By Value
auto func4 = std::bind([](std::unique_ptr< std::vector<int> > pw) // error
{
    std::cout << "size of vector4: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));
func4(); // without this line, compilation is fine. The VS generates error for the calling of the bind object.
// By r-value reference
auto func5 = std::bind([](std::unique_ptr< std::vector<int> >&& pw) // error
{
    std::cout << "size of vector5: " << pw->size() << std::endl;
}, std::make_unique<std::vector<int>>(22, 1));
func5(); // without this line, compilation is fine.

为什么func4和func5无法编译?

2 个答案:

答案 0 :(得分:4)

func4产生错误,因为lambda的参数是按值传递的。但std::unique_ptr不可复制。

func5更复杂,我们可以阅读文档std::bind

  

给定从早先的bind调用中获得的对象g,当在函数调用表达式g(u1, u2, ... uM)中调用它时,就会发生对存储对象的调用,就像std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN))一样,其中{ {1}}是fd类型的值,绑定参数std::decay_t<F>v1,...,v2的值和类型如下所示确定。<登记/>   ...
  普通存储的参数vN 作为lvalue参数传递给invokable对象:上面的std :: invoke调用中的参数arg只是arg和相应的类型{{ 1}}是vn,其中 cv Vn的cv资格相同。

因此,即使T cv &是r值,也会给lambda一个l值,这与预期的r值不兼容。
这也可以解释为什么g工作正常。

答案 1 :(得分:2)

bind返回一个可以多次调用的函数对象。

它接受参数并将其存储在元组(或等价物)中。然后它用其余的调用第一个参数。这类似于C ++ 17中的std::invoke

对于两个失败的案例,你不能多次调用lambda。因此,当您调用一次时会出现错误,因为 bind假定您希望能够再次调用它。做其他事情会很疯狂,因为它无法知道你在operator()的背景下再也没有再调用它。

逻辑上,那些的调用应该失败。该标准还要求它们失败,因为这种情况下的标准在逻辑上表现出来。

auto funcA =
  [pw=std::make_unique<std::vector<int>>(22,1)]
  {
    std::cout << "size of vector2: " << pw->size() << std::endl;
  };

auto funcB =
  [pw=std::make_unique<std::vector<int>>(22,1)]() mutable
  {
    std::cout << "size of vector2: " << pw->size() << std::endl;
  };

这里有两个不同的lambda,大致与你的代码相同。我们只是捕获而不是绑定和传递。

funcA我们有一个const unique_ptr,在funcB我们有一个非const unique_ptr。在第二个,我们可以走出独特的ptr;在第一,我们不能。

std::bind是在使用C ++存在的lambda之前编写的,并且它很少比使用lambda更好。 lambdas的缺陷大部分已被C ++ 14删除,并且很少有使用bind而不是lambda的情况是个好主意。

std::bind会生成神秘的错误消息,并且会在一些极端情况下产生神秘的行为,例如将bind的结果传递给另一个bind