// 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无法编译?
答案 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
。