M. *_* E. 17 c++ function stdbind c++11
例如,这是我的成员函数(do_it
):
class oops
{
public:
void do_it(GtkWidget *widget, GdkEvent *event, gpointer data)
{
g_print ("Hi there :)\n");
}
};
Run Code Online (Sandbox Code Playgroud)
...我用std::bind
它来使它看起来像一个非成员函数:
oops o;
std::function<void(GtkWidget*, GdkEvent*, gpointer)> f = std::bind(&oops::do_it, o);
Run Code Online (Sandbox Code Playgroud)
但它不起作用,以下是编译器错误消息:
program.cc: In function ‘int main(int, char**)’:
program.cc:69:85: error: conversion from ‘std::_Bind_helper<false, void (oops::*)(_GtkWidget*, _GdkEvent*, void*), oops&>::type {aka std::_Bind<std::_Mem_fn<void (oops::*)(_GtkWidget*, _GdkEvent*, void*)>(oops)>}’ to non-scalar type ‘std::function<void(_GtkWidget*, _GdkEvent*, void*)>’ requested
std::function<void(GtkWidget*, GdkEvent*, gpointer)> f = std::bind(&oops::do_it, o);
^
Run Code Online (Sandbox Code Playgroud)
我必须使用std::placeholders
以下方法修复它:
oops o;
std::function<void(GtkWidget*, GdkEvent*, gpointer)> f = std::bind(&oops::do_it, o, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
Run Code Online (Sandbox Code Playgroud)
为什么没有指定它不起作用std::placeholders
?
Man*_*726 47
std::bind()
用于创建一个可调用的实体,表示对函数的(部分)调用.它将调用的一些参数绑定到生成的调用对象,并在调用时将其余参数设置为:
void f(int,int,int);
int main()
{
std::function<void()> f_call = std::bind( f , 1 , 2 , 3);
f_call(); //Equivalent to f(1,2,3)
}
Run Code Online (Sandbox Code Playgroud)
第一个参数std::bind()
是要调用的函数,其余的是调用的参数.
在此示例中,生成调用对象时指定了所有三个参数,因此调用点没有参数.现在考虑部分定义的调用:
std::function<void(int,int,int)> f_call = std::bind( f );
Run Code Online (Sandbox Code Playgroud)
这不编译,因为该函数有三个参数,你没有指定任何一个!这没有意义,对吧?如果您有一个具有三个参数的函数,则应将三个参数传递给调用对象.
如果需要指定必须在调用点指定某些参数,则必须使用占位符来表示该参数.例如:
using namespace std::placeholders;
std::function<void(int,int,int)> f_call = std::bind( f , _1 , _2 , _3 );
f_call( 1 , 2 , 3 ); //Same as f(1,2,3)
Run Code Online (Sandbox Code Playgroud)
如您所见,我们使用占位符为函数调用指定了三个"空格",即在调用点指定的三个参数.
请注意,占位符的数字指定呼叫点处的参数编号.呼叫点的第一个参数由_1
第二个依据标识_2
,依此类推.这可用于以不同方式指定参数,重新排序函数调用的参数等.例如:
std::function<void(int,int)> f_call = std::bind( f , _1 , 2 , _2 );
f_call( 1 , 3 ); //Equivalent to f( 1 , 2 , 3 );
std::function<void(int,int,int)> reordered_call = std::bind( f , _3 , _2 , _1 );
reordered_call( 3 , 2 , 1 ); //Same as f( 1 , 2 , 3 );
Run Code Online (Sandbox Code Playgroud)
最后,std::bind()
可以用于将成员函数绑定到用于调用它的对象:
struct foo
{
void f() const;
};
int main()
{
foo myfoo;
std::function<void()> f = std::bind( &foo::f , std::cref( myfoo ) );
f(); //Tah dah!
}
Run Code Online (Sandbox Code Playgroud)
可以将成员函数视为具有一个隐藏参数的函数,该参数是完成调用的对象.这就是为什么对象被绑定为第一个参数.
但是,与上面的示例完全相同,如果您只在绑定点知道一定数量的参数,并且需要稍后在调用点指定其他参数,则应使用占位符:
using namespace std::placeholders;
oops o;
std::function<GtkWidget*,GtkEvent*,gpointer> do_it = std::bind( &oops::do_it , std::ref( o ) , _1 , _2 , _3 );
do_it( /* first param */ , /*second param */ , /* third param */ ); //Call
Run Code Online (Sandbox Code Playgroud)
请注意,我们std::function
用来存储调用对象.该函数的签名取决于生成的调用对象的类型,即取决于您在绑定点指定参数的方式.
调用对象只是另一个可调用的实体,它充当对原始函数的调用.以下是我们的f()
功能示例:
std::function<void()> f_call = std:bind( f , 1 , 2 , 3 );
Run Code Online (Sandbox Code Playgroud)
这里调用对象的签名是void()
,因为我们在绑定点指定了一组参数,并且在调用点没有指定任何一个(因此调用对象没有参数).
在部分呼叫的情况下:
std::function<void(int,int,int)> f_call = std::bind( f, _1 , _2 , _3 );
f_call( 1 , 2 , 3 );
Run Code Online (Sandbox Code Playgroud)
调用对象的签名是void(int,int,int)
,因为我们在调用点处留下了三个参数(注意占位符).通常,调用对象具有与您在绑定点指定的占位符相同数量的参数..