std::bind 和右值引用
std::bind and rvalue reference
让我们考虑以下代码:
class Widget{
};
int main(){
Widget w;
auto lambda = bind([](Widget&& ref){ return; }, std::move(w));
return 0;
}
并触发错误
no match for call to ‘(std::_Bind<main()::<lambda(Widget&&)>(Widget)>) ()’
lambda();
我的问题是:为什么会出现错误?毕竟,我对右值引用进行了显式转换——我的意思是 std::move(w)
并且我通过右值引用进行论证——我的意思是 Widget&& ref
.
怎么了?
而且下面的代码是有效的,更让我担心的是:
class Widget{
};
int main(){
Widget w;
auto lambda = bind([](Widget& ref){ return; }, std::move(w));
return 0;
}
如果您写下 std::bind
的示意性作用,可能会更清楚。
// C++14, you'll have to write a lot of boilerplate code for C++11
template <typename FuncT, typename ArgT>
auto
bind(FuncT&& func, ArgT&& arg)
{
return
[
f = std::forward<FuncT>(func),
a = std::forward<ArgT>(arg)
]() mutable { return f(a); }; // NB: a is an lvalue here
}
因为你可以多次调用std::bind
给你的函数对象,它不能“用完”捕获的参数,所以它会作为左值引用传递。您将 bind
本身传递给右值这一事实仅意味着在初始化 a
的行上没有进行复制。
如果您尝试使用上面显示的原理图 bind
编译您的示例,您还会从编译器中获得更有用的错误消息。
main.cxx: In instantiation of ‘bind(FuncT&&, ArgT&&)::<lambda()> mutable [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’:
main.cxx:10:33: required from ‘struct bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]::<lambda()>’
main.cxx:11:31: required from ‘auto bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’
main.cxx:18:59: required from here
main.cxx:11:26: error: no match for call to ‘(main()::<lambda(Widget&&)>) (Widget&)’
]() mutable { return f(a); }; // NB: a is an lvalue here
^
main.cxx:11:26: note: candidate: void (*)(Widget&&) <conversion>
main.cxx:11:26: note: conversion of argument 2 would be ill-formed:
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
main.cxx:18:33: note: candidate: main()::<lambda(Widget&&)> <near match>
auto lambda = bind([](Widget&&){ return; }, std::move(w));
^
main.cxx:18:33: note: conversion of argument 1 would be ill-formed:
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
]() mutable { return f(a); }; // NB: a is an lvalue here
要让它工作,你需要这样写:
#include <functional>
#include <iostream>
class Widget{};
int main()
{
Widget a;
auto lf = [](Widget&& par){ };
auto f = std::bind
(
lf,
std::bind
(
std::move<Widget&>, a
)
);
f();
return 0;
}
我的编译器是gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)
让我们考虑以下代码:
class Widget{
};
int main(){
Widget w;
auto lambda = bind([](Widget&& ref){ return; }, std::move(w));
return 0;
}
并触发错误
no match for call to ‘(std::_Bind<main()::<lambda(Widget&&)>(Widget)>) ()’
lambda();
我的问题是:为什么会出现错误?毕竟,我对右值引用进行了显式转换——我的意思是 std::move(w)
并且我通过右值引用进行论证——我的意思是 Widget&& ref
.
怎么了?
而且下面的代码是有效的,更让我担心的是:
class Widget{
};
int main(){
Widget w;
auto lambda = bind([](Widget& ref){ return; }, std::move(w));
return 0;
}
如果您写下 std::bind
的示意性作用,可能会更清楚。
// C++14, you'll have to write a lot of boilerplate code for C++11
template <typename FuncT, typename ArgT>
auto
bind(FuncT&& func, ArgT&& arg)
{
return
[
f = std::forward<FuncT>(func),
a = std::forward<ArgT>(arg)
]() mutable { return f(a); }; // NB: a is an lvalue here
}
因为你可以多次调用std::bind
给你的函数对象,它不能“用完”捕获的参数,所以它会作为左值引用传递。您将 bind
本身传递给右值这一事实仅意味着在初始化 a
的行上没有进行复制。
如果您尝试使用上面显示的原理图 bind
编译您的示例,您还会从编译器中获得更有用的错误消息。
main.cxx: In instantiation of ‘bind(FuncT&&, ArgT&&)::<lambda()> mutable [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’:
main.cxx:10:33: required from ‘struct bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]::<lambda()>’
main.cxx:11:31: required from ‘auto bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’
main.cxx:18:59: required from here
main.cxx:11:26: error: no match for call to ‘(main()::<lambda(Widget&&)>) (Widget&)’
]() mutable { return f(a); }; // NB: a is an lvalue here
^
main.cxx:11:26: note: candidate: void (*)(Widget&&) <conversion>
main.cxx:11:26: note: conversion of argument 2 would be ill-formed:
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
main.cxx:18:33: note: candidate: main()::<lambda(Widget&&)> <near match>
auto lambda = bind([](Widget&&){ return; }, std::move(w));
^
main.cxx:18:33: note: conversion of argument 1 would be ill-formed:
main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
]() mutable { return f(a); }; // NB: a is an lvalue here
要让它工作,你需要这样写:
#include <functional>
#include <iostream>
class Widget{};
int main()
{
Widget a;
auto lf = [](Widget&& par){ };
auto f = std::bind
(
lf,
std::bind
(
std::move<Widget&>, a
)
);
f();
return 0;
}
我的编译器是gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)