Binding functions with unique_ptr arguments to std::function<void()>
c++, c++11
Solution
The issues with bind described in the other answers (as of this writing) are not what the compiler is complaining about in the question. The problem is that `std::function` must be CopyConstructible, which requires its argument (which will be stored by the function) also be CopyConstructible.
From the standard [20.9.11.2 Class template function]
template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);
Requires: F shall be CopyConstructible. f shall be Callable (20.9.11.2) for argument types ArgTypes and return type R . The copy constructor and destructor of A shall not throw exceptions...
Consider this example that doesn't even include bind in it:
#include <functional>
#include <memory>
using namespace std;
struct NonCopyableFunctor {
NonCopyableFunctor(){}
NonCopyableFunctor(const NonCopyableFunctor &) = delete;
NonCopyableFunctor(NonCopyableFunctor &&){}
void operator()(){}
};
int main()
{
NonCopyableFunctor fun;
function<void()> vfun(move(fun)); // even though I move here,
// it still complains about a copy going on elsewhere.
}
Here's the output from clang:
[orm@localhost ~]$ clang++ -std=c++11 bound_unique.cc
In file included from bound_unique.cc:1:
/usr/bin/../lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/functional:1911:10: error: call to deleted constructor of 'NonCopyableFunctor'
new _Functor(*__source._M_access<_Functor*>());
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/functional:1946:8: note: in instantiation of member function
'std::_Function_base::_Base_manager<NonCopyableFunctor>::_M_clone' requested here
_M_clone(__dest, __source, _Local_storage());
^
/usr/bin/../lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/functional:2453:33: note: in instantiation of member function
'std::_Function_base::_Base_manager<NonCopyableFunctor>::_M_manager' requested here
_M_manager = &_My_handler::_M_manager;
^
bound_unique.cc:16:20: note: in instantiation of function template specialization 'std::function<void ()>::function<NonCopyableFunctor, void>' requested here
function<void()> vfun(move(fun));
^
bound_unique.cc:8:3: note: function has been explicitly marked deleted here
NonCopyableFunctor(const NonCopyableFunctor &) = delete;
^
1 error generated.
Note that if you bind a unique_ptr, the resulting bind object will be non-copyable. Bind will still compile anyway.
Problem
I'm trying to make the following code work: ``` #include <cstdio> #include <functional> #include <string> #include <memory> using namespace std; class Foo { public: Foo(): m_str("foo") { } void f1(string s1, string s2, unique_ptr<Foo> p) { printf("1: %s %s %s\n", s1.c_str(), s2.c_str(), p->str()); } void f2(string s1, string s2, Foo* p) { printf("2: %s %s %s\n", s1.c_str(), s2.c_str(), p->str()); } const char* str() const { return m_str.c_str(); } private: string m_str; }; int main() { string arg1 = "arg1"; string arg2 = "arg2"; Foo s; unique_ptr<Foo> ptr(new Foo); //function<void()> f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); function<void()> f(bind(&Foo::f2, &s, arg1, arg2, ptr.release())); f(); } ``` Calling `f()` bound to `Foo::f2` (last parameter is a raw pointer) works fine, but binding it to `Foo::f1` causes compilation error: ``` test.cpp: In function ‘int main()’: test.cpp:36:70: error: no matching function for call to ‘std::function<void()>::function(std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type)’ function<void()> f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); ^ test.cpp:36:70: note: candidates are: In file included from test.cpp:2:0: /usr/include/c++/4.8.2/functional:2251:2: note: template<class _Functor, class> std::function<_Res(_ArgTypes ...)>::function(_Functor) function(_Functor); ^ /usr/include/c++/4.8.2/functional:2251:2: note: template argument deduction/substitution failed: /usr/include/c++/4.8.2/functional:2226:7: note: std::function<_Res(_ArgTypes ...)>::function(std::function<_Res(_ArgTypes ...)>&&) [with _Res = void; _ArgTypes = {}] function(function&& __x) : _Function_base() ^ /usr/include/c++/4.8.2/functional:2226:7: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type {aka std::_Bind<std::_Mem_fn<void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>(Foo*, std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>}’ to ‘std::function<void()>&&’ /usr/include/c++/4.8.2/functional:2429:5: note: std::function<_Res(_ArgTypes ...)>::function(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {}] function<_Res(_ArgTypes...)>:: ^ /usr/include/c++/4.8.2/functional:2429:5: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type {aka std::_Bind<std::_Mem_fn<void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>(Foo*, std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>}’ to ‘const std::function<void()>&’ /usr/include/c++/4.8.2/functional:2206:7: note: std::function<_Res(_ArgTypes ...)>::function(std::nullptr_t) [with _Res = void; _ArgTypes = {}; std::nullptr_t = std::nullptr_t] function(nullptr_t) noexcept ^ /usr/include/c++/4.8.2/functional:2206:7: note: no known conversion for argument 1 from ‘std::_Bind_helper<false, void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>), Foo*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::unique_ptr<Foo, std::default_delete<Foo> > >::type {aka std::_Bind<std::_Mem_fn<void (Foo::*)(std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>(Foo*, std::basic_string<char>, std::basic_string<char>, std::unique_ptr<Foo>)>}’ to ‘std::nullptr_t’ /usr/include/c++/4.8.2/functional:2199:7: note: std::function<_Res(_ArgTypes ...)>::function() [with _Res = void; _ArgTypes = {}] function() noexcept ^ /usr/include/c++/4.8.2/functional:2199:7: note: candidate expects 0 arguments, 1 provided ``` What am I doing wrong? I'm using gcc 4.8.2 and `-std=c++0x` (`-std=c++11` fails too) flags.