我们在这里定义了三个类:函数基类CFuncitonBase,模板函数类CFunction(公有继承CFuntionBase),以及进程类Myprocess。
目的是实现进程函数的外部初始化:通过Myprocess类内的SetFunction模板函数和模板函数类CFunction的构造函数相配合,在外部确定类对象的实际运行函数。调用过程如下图所示:
using namespace std;
int sum(int a, int b) {
cout << a << endl;
cout << b << endl;
return a + b;
}
class CFunctionBase {
private:
public:
virtual ~CFunctionBase() {}
virtual int operator()() { return 0; };
};
template
class CFunction:public CFunctionBase {
public:
~CFunction() {}
int operator()() {return m_binder();}
CFunction(_FUNCTION_ func, _ARGS_... args)
:m_binder(std::forward<_FUNCTION_>(func), std::forward<_ARGS_>(args)...) {
}
typename std::_Bindres_helper::type m_binder;
};
class MyProcess {
private:
CFunctionBase* m_func = nullptr;
public:
template
int SetFunction(_FUNCTION_ func, _ARGS_... args) {
m_func = new CFunction<_FUNCTION_, _ARGS_...>(func, args...);
return 0;
}
int Start() {
pid_t pid = fork();
if (pid == 0) {
(*m_func)();
exit(0);
}
//注意父进程还会从这里运行下去,这个过程是异步的,相当于if(pid>0) return;
}
public:
MyProcess() {}
~MyProcess() { m_func = nullptr; }
};
int main() {
MyProcess process;
process.SetFunction(sum,1,2);
process.Start();
return 0;
}
c++11中有29个占位符,分别是_1~_29,一般情况下是写std::placeholders::_1这样子的。占位符的作用就是用来代表参数的,std::placeholders::_1表示的是std::bind得到的std::function对象被调用时,传入的第一个参数,而std::placeholders::_2则是第二个参数。
我们调整std::placeholders::_x在std::bind时的顺序,就可以起到调整参数顺序的作用了。此外,我们也可以在std::bind的时候不用std::placeholders::_x,而直接写成固定的值,这样子调用std::function存储的对象时,对应位置的参数将是固定值。
int sum(int a, int b) {
cout << a << endl;
cout << b << endl;
return a + b;
}
int main() {
auto func= std::bind(sum, std::placeholders::_2, std::placeholders::_1);
std::cout << func(1, 2) << endl;//output: 2,1
return 0;
}
当我创建一个进程对象并已经将一个普通函数/静态函数设置为该进程的运行函数,如果在运行过程中我还需要进一步再提供部分数据传入这个函数内部,那么原先设置好的特征标/参数列表已不能再满足我的需求。那么我可以通过占位符为CFunction模板函数构建时再增加一部分不清楚具体内容的特定类型参数,可运行代码如下:
举个例子:一个服务器进程,循环等待客户的连接。等到接收到客户的连接,送给线程池处理(服务器在处理客户端的连接一般是事先初始化多个线程,而不是遇到连接再创建线程,换句话说,线程的创建也是消耗资源和时间的)。这个过程中,线程并不事先知道用户的连接信息(一般是一个socket内容),那么在处理任务时,就需要将这个套接字传入,或者再传入一些额外字符串数据。
using namespace std;
int sum(int a, int b) ;
cout << a << endl;
cout << b << endl;
return a + b;
}
class CFunctionBase {
private:
public:
virtual ~CFunctionBase() {}
virtual int operator()(int b) { return 0; };//替换了之前的virtual int operator()() { return 0; };如果保留会报错
};
template
class CFunction :public CFunctionBase {
public:
~CFunction() {}
virtual int operator()(int b) { //替换了之前的int operator()() {return m_binder();}如果保留会报错
return m_binder(b);
}
CFunction(_FUNCTION_ func, _ARGS_... args)
:m_binder(std::forward<_FUNCTION_>(func), std::forward<_ARGS_>(args)...) {
}
typename std::_Bindres_helper::type m_binder;
}
};
class MyProcess {
private:
CFunctionBase* m_func = nullptr;
public:
template
int SetFunction(_FUNCTION_ func, _ARGS_... args) {
m_func = new CFunction<_FUNCTION_, _ARGS_...>(func, args...);
return 0;
}
int Start(int b) {//Start传入int
pid_t pid = fork();
if (pid == 0) {
(*m_func)(b);//在运算符重载函数中传入b
exit(0);
}
}
private:
CFunctionBase* m_func = nullptr;
public:
//其他不变
};
int main() {
MyProcess process;
process.SetEntryFunction(sum,1, std::placeholders::_1);
process.Start(4);
return 0;
}
如果之前CFunctionBase和CFunction的不带参数()重载运算符继续保留,即:
class CFunctionBase {
private:
public:
virtual ~CFunctionBase() {}
virtual int operator()() { return 0; };
virtual int operator()(int b) { return 0; };
};
template
class CFunction :public CFunctionBase {
public:
~CFunction() {}
virtual int operator()() {return m_binder();}
virtual int operator()(int b) { //替换了之前的如果保留会报错
return m_binder(b);
}
CFunction(_FUNCTION_ func, _ARGS_... args)
:m_binder(std::forward<_FUNCTION_>(func), std::forward<_ARGS_>(args)...) {
}
typename std::_Bindres_helper::type m_binder;
}
};
这时使用编译器生成可执行文件将报错如下所示:
std::_Mu:用于匹配占位符的模板类
std::_Mu< _Arg, _IsBindExp, _IsPlaceholder >
Detailed Description
template
class std::_Mu< _Arg, _IsBindExp, _IsPlaceholder >"Maps an argument to bind() into an actual argument to the bound function object [func.bind.bind]/10. Only the first parameter should be specified: the rest are used to determine among the various implementations. Note that, although this class is a function object, it isn’t entirely normal because it takes only two parameters regardless of the number of parameters passed to the bind expression. The first parameter is the bound argument and the second parameter is a tuple containing references to the rest of the arguments.
类功能:将 bind() 的参数映射到绑定函数对象的实际参数。只应指定第一个参数:其余参数用于确定各种实现。请注意,尽管此类是一个函数对象,但它并不完全正常,因为无论传递给绑定表达式的参数数量如何,它都只接受两个参数。第一个参数是绑定参数,第二个参数是包含对其余参数的引用的元组。
std::is_bind_expression用于判断是否是bind表达式,有value成员,返回值是true或false
std::is_placeholder 用于判断T是否为占位符,它有一个成员变量value。如果T是placeholder类型,value的值为1代表 _1,2代表 _2;如果T不是,则value为0。
我们可以看出对于operator()()无参运算符重载函数,std::_Mu函数无法找到可以匹配的参数对象,即占位符std::Placehoder_1无法从现有的参数列表中找到合适的目标,因存在这种无法正确调用的函数,所以函数无法通过编译。
换句话说,我们可以将其简单化为如下代码(参考C++ 模板法实现进程创建和占位符placeholders应用的奇妙反应):
using namespace std;
int sum(int a, int b) {
cout << a << endl;
cout << b << endl;
return a + b;
}
int main() {
auto func = std::bind(sum, 1, std::placeholders::_1);
std::cout << func() << endl;
return 0;
}
在sum需要b运算符时,占位符1从func中找不到参数,因而报错如下:
因此,对于提前告诉进程对象Myprocess A.SetEntryFunction(sum,1, std::placeholders::_1);,编译器在编译时发现在空参数()重载运算符执行时,无法正确匹配参数,因而存在这种风险Error,就算你后面不会在这个对象调用这个空参数方法,也编译不通过。当然你可以在空参数括号重载运算符内直接输入一个常数作为参数:int operator()() {return m_binder(123456);}
,但这样这个函数就失去了本身存在的意义。
我们可以为需要传入额外参数的对象重新定义一个继承自CFunctionBase类的CFuntion-N代,不同类定义不同参数的()运算符重载函数(但是,你需要在CFunctionBase类定义时为所有派生类的运算符重载函数都定义一个无意义但让编译通过的同名同参数虚函数,所有派生类CFunction-?代的函数都需要定义),如下所示:
class CFunctionBase {
private:
public:
virtual ~CFunctionBase() {}
virtual int operator()() { return 0; };//return -1/0均可
virtual int operator()(int P1) { return 0; };
virtual int operator()(int P1,int P2) { return 0; };
};
template
class CFunction :public CFunctionBase {
public:
CFunction(_FUNCTION_ func, _ARGS_... args)
:m_binder(std::forward<_FUNCTION_>(func), std::forward<_ARGS_>(args)...) {}
typename std::_Bindres_helper::type m_binder;
virtual ~CFunction() {}
virtual int operator()() { return m_binder(); }
private:
};
template
class CFunction_1:public CFunctionBase {
public:
CFunction_1(_FUNCTION_ func, _ARGS_... args)
:m_binder(std::forward<_FUNCTION_>(func), std::forward<_ARGS_>(args)...) {}
typename std::_Bindres_helper::type m_binder;
virtual ~ CFunction_1() {}
virtual int operator()(int P1) {
return m_binder(P1);
}
private:
}
template
class CFunction_2:public CFunctionBase {
public:
CFunction_2(_FUNCTION_ func, _ARGS_... args)
:m_binder(std::forward<_FUNCTION_>(func), std::forward<_ARGS_>(args)...) {}
typename std::_Bindres_helper::type m_binder;
virtual ~ CFunction_2() {}
virtual int operator()(int P1,int P2) {
return m_binder(P1,P2);
}
private:
};