我正在尝试使以下代码工作:
#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();
}
调用f()绑定到Foo :: f2(最后一个参数是一个原始指针)工作正常,但将其绑定到Foo :: f1会导致编译错误:
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
我究竟做错了什么?
我正在使用gcc 4.8.2和-std = c 0x(-std = c 11也失败)标志 .
谢谢
3 回答
嗯,看起来std :: bind在处理r值引用时遇到了麻烦 . 一种替代方法是使用lambda函数:
为了使其工作,您还必须更改f1的签名,使其接受unique_ptr作为r值引用:
(即使std :: bind可以处理r值引用,你仍然必须这样做,因为std :: unique_ptr没有复制构造函数,只有移动构造函数是可访问的!)
但请注意,你的构造是相当危险的(如果std :: bind可以工作):如果你调用f()两次,你将最终得到一个运行时异常 .
1)以下代码不会编译
因为
function
要求可调用对象是可复制构造的,但是当bind
采用不可复制的参数(如unique_ptr
)时,返回的仿函数将是不可复制的,如其他答案中所述 .2)所以只是不要
function
用于bind
. 但是,以下代码也不会编译因为在步骤(a)
bind
存储您作为左值给出的值(reference_wrapper
除外),并在步骤(b)将其传递给内部函子 . 因此,它要求绑定参数是可复制的,因为那些参数是通过值传递的,而不是引用 .3)然后尝试使用原始指针 . 但是,以下代码也不会编译
与(2)类似的原因,仿函数存储
int*
,并在调用时尝试将其转换为参数类型unique_ptr<int>
. 但构造函数unique_ptr(pointer p)
是explicit
.要编译它,你需要一个像这样的函数
请注意,
f
可以多次调用,参数p
引用存储在bind
的返回对象中的相同unique_ptr
.其他答案中描述的bind问题(截至本文撰写时)并不是编译器在问题中抱怨的问题 . 问题是
std::function
必须是CopyConstructible,这需要它的参数(将由函数存储)也是CopyConstructible .从标准[20.9.11.2类模板功能]
考虑这个甚至不包含绑定的示例:
这是clang的输出:
请注意,如果绑定unique_ptr,则生成的绑定对象将是不可复制的 . Bind仍然会编译 .