2017-03-02 120 views
4
// 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无法编译?在std :: unique_ptr中使用std :: bind in lambda

+0

你的代码在VS2015中编译得很好。请在你身边显示错误信息。 –

+0

@Martin Zhai,如果添加func4()或func5()这一行,那么你会看到很多错误。 – q0987

+1

你的主要问题是使用'std :: bind'。在发生第一次错误之后,你也会(可以预料地)发现其他错误。 – Yakk

回答

4

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

func5是更复杂的,我们可以从文档std::bind读:

给定来自先前调用结合,当在一个函数调用表达式g(u1, u2, ... uM)被调用时,所存储的的调用获得的对象克对象发生,好像通过std::invoke(fd, std::forward<V1>(v1), std::forward<V2>(v2), ..., std::forward<VN>(vN)),其中fd是类型std::decay_t<F>的值,绑定参数v1v2,...,vN的值和类型按照以下规定来确定。
...
普通存储参数arg被传递给可调用对象作为左值参数:在STD中的参数vn ::调用呼叫上面简单Arg和相应的类型VnT cv &,其中CVg具有相同的简历资格。

因此,即使std::make_unique<std::vector<int>>(22, 1)是r值,也会给λ值赋予l值,这与预期的r值不兼容。
这也可以解释为什么func3工作正常。

2

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

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

对于您的两个失败案例,您都不能多次调用lambda。因此,当您调用一次时出现错误,因为绑定假定您想要再次调用它。做其他事情将是疯狂的,因为它不知道你从来没有再次呼吁它在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我们有一个非constunique_ptr。第二,我们可以搬出独特的ptr;在第一个,我们不能。

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

std::bind会产生神秘的错误消息,并在一些角落案例中具有神秘的行为,如将bind的结果传递给另一个bind