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.
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.
1) The following code won't compile
function<void()> f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr)));
// just define f, not even call it
because function
requires the callable object is copy-constructible but when bind
takes a non-copyable argument like unique_ptr
the returned functor will be non-copyable, as mentioned in other answers.
2) So just don't use function
for bind
. However the following code won't compile either
auto f(bind(&Foo::f1, &s, arg1, arg2, std::move(ptr))); // a
f(); // b
because at step (a) bind
stores what you give to it as an lvalue (except for reference_wrapper
), and passes it to the internal functor at step (b). Therefore it requires the bound arguments are copyable for those parameters are passed by value, not references.
3) Then try using the raw pointer. However the following code won't compile either
auto f(bind(&Foo::f1, &s, arg1, arg2, ptr.release()));
f();
A similar reason like (2), the functor stores an int*
, and try to convert it to the parameter type unique_ptr<int>
when called. But the constructor unique_ptr(pointer p)
is explicit
.
To compile it, you need a function like this
void f3(string s1, string s2, unique_ptr<Foo>& p)
// ^ use reference; add const if you need
{
printf("3: %s %s %s\n", s1.c_str(), s2.c_str(), p->str());
}
auto f(bind(&Foo::f3, &s, arg1, arg2, std::move(ptr)));
f();
Note that f
could be called several times, and the parameters p
reference the same unique_ptr
that is stored in the returned object of bind
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With