我们在使用C++的函数绑定功能时,每次都需要写一大堆的占位符,有多少个参数就要写多少个占位符,比如下面的示例代码:
class CTest
{
public:
void foo1(int a, string& b, float c, double d, void* p);
void foo2(int a, string& b, float c, double d, void* p, short f);
};
int main()
{
CTest t;
// 由于CTest::foo1有5个参数,所以这里使用函数绑定时需要写5个占位符
auto f1 = std::bind(&CTest::foo1, &t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,std::placeholders::_4, std::placeholders::_5);
// 由于CTest::foo1有6个参数,所以这里使用函数绑定时需要写6个占位符
auto f2 = std::bind(&CTest::foo2, &t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,std::placeholders::_4, std::placeholders::_5, std::placeholders::_6);
return 0;
}
每个绑定都需要根据函数的参数个数写对应个占位参数,个人感觉很麻烦,所以想省略这些占位参数。根据C++ 11的模板参数允许可变的特性,我写了如下一段代码,以自动推导参数个数并且自动填充,甚是方便。独乐乐不如众乐乐,分享出来共大家使用:
#if _MSC_VER
#define PlaceHolder std::_Ph
#else
#define PlaceHolder std::_Placeholder
#endif
template
struct MakeSeqs : MakeSeqs {};
template
struct MakeSeqs<1, I...>
{
template
static auto bind(T* obj, R(T::*_Func)(Args...)) -> decltype(std::bind(_Func, obj, PlaceHolder{}...))
{
return std::bind(_Func, obj, PlaceHolder{}...);
}
};
template
auto Bind(T* t, R(T::*f)(Args...)) -> decltype(MakeSeqs::bind(t, f))
{
return MakeSeqs::bind(t, f);
}
template
auto Bind(R(T::*f)(Args...), T* t) -> decltype(MakeSeqs::bind(t, f))
{
return MakeSeqs::bind(t, f);
}
由于C++11的auto不能完全自动推导类型,所以auto返回类型的函数后面需要写decltype。如果使用C++ 14则更简洁:
#if _MSC_VER
#define PlaceHolder std::_Ph
#else
#define PlaceHolder std::_Placeholder
#endif
template
struct MakeSeqs : MakeSeqs {};
template
struct MakeSeqs<1, I...>
{
template
static auto bind(T&& obj, _Fx&& _Func)
{
return std::bind(std::forward<_Fx>(_Func), std::forward(obj), PlaceHolder{}...);
}
};
template
auto Bind(T* t, R(T::*f)(Args...))
{
return MakeSeqs::bind(t, f);
}
template
auto Bind(R(T::*f)(Args...), T* t)
{
return MakeSeqs::bind(t, f);
}
有了这段辅助代码,前面的示例代码的main函数就可以改写成:
int main()
{
CTest t;
auto f1 = Bind(&CTest::foo1, &t);
auto f2 = Bind(&CTest::foo2, &t);
return 0;
}
是不是感觉清爽多了?
以上代码在VS2015以及GCC4.9.3以上版本编译通过,GCC需要使用-std=c++11或者-std=c++14参数进行编译。
祝好!