As I understand it,
std::bind
perfectly forwards both the callable object it wraps and the arguments to that callable object;- the
std::bind
return object is itself movable and/or copyable, depending on whether the callable object and its arguments are movable and/or copyable; - a
std::bind
return object may be nested, in which case the outerstd::bind
return object is movable and/or copyable, just as when binding other callable objects.
Therefore, I would expect the following code snippet to compile okay. Instead, the code generates a spew of compiler errors at the last two statements in main()
.
#include <functional>
template<typename HandlerType>
void call_handler(HandlerType&& handler)
{
handler();
}
template<typename HandlerType>
void do_something(HandlerType&& handler)
{
auto f = std::bind(
&call_handler<HandlerType&>,
std::forward<HandlerType>(handler));
f();
}
int main()
{
auto a = [&]() {};
do_something(a);
do_something(std::move(a));
auto b = std::bind([&]() {});
do_something(b); // <- compiler error!
do_something(std::move(b)); // <- compiler error!
}
Each of the two problem line spews errors without the other. To eliminate all errors, I must comment out both lines.
Here's a sample error, from g++ 4.9.2 in Cygwin, at the call to f()
in do_something()
:
(4 of 103): error: no match for call to ‘(std::_Bind<void (*(std::_Bind<main()::<lambda()>()>))(std::_Bind<main()::<lambda()>()>&)>) ()’
Here's a sample error from Visual Studio 2013, at the same line:
1>C:\Program Files (x86)\Microsoft Visual Studio12.0\VC\include\functional(1149): error C2664: 'void (HandlerType)' : cannot convert argument 1 from 'void' to 'std::_Bind<false,void,main::<lambda_2b8ed726b4f655ffe5747e5b66152230>,> '
What's going on? Do I misunderstand std::bind
?
Specifically, how can I
- bind a callable object? and
- pass that
std::bind
return object to a function taking a universal reference? and - nest that
std::bind
return object in anotherstd::bind
?
My goal is for the underlying callable object and its arguments to be perfectly forwarded.
EDIT: To clarify, I want to pass the wrapped callable object and its arguments by value, not by reference, so std::ref
won't help—at least, not as a full solution. The reason is that my real code is more complex and involves passing the f
std::bind
return object across a thread boundary, and both the a
and b
std::bind
return objects may go out of scope in the original thread before call_handler
calls f()
, so a
and b
need to copy or move into f
, not be mere references. That said, my question is specifically about std::bind
and perfect forwarding, and for the purpose of asking a good question, I've distilled out everything not needed to reproduce the specific compiler errors I mentioned.