我们在使用C++的函数绑定功能时,每次都需要写一大堆的占位符,有多少个参数就要写多少个占位符,比如下面的示例代码:

 1class CTest
 2{
 3public:
 4	void foo1(int a, string& b, float c, double d, void* p);
 5	void foo2(int a, string& b, float c, double d, void* p, short f);
 6};
 7
 8int main()
 9{
10	CTest t;
11	// 由于CTest::foo1有5个参数,所以这里使用函数绑定时需要写5个占位符
12	auto f1 = std::bind(&CTest::foo1, &t, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,std::placeholders::_4, std::placeholders::_5);
13	// 由于CTest::foo1有6个参数,所以这里使用函数绑定时需要写6个占位符
14	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);
15	return 0;
16}

每个绑定都需要根据函数的参数个数写对应个占位参数,个人感觉很麻烦,所以想省略这些占位参数。根据C++ 11的模板参数允许可变的特性,我写了如下一段代码,以自动推导参数个数并且自动填充,甚是方便。独乐乐不如众乐乐,分享出来共大家使用:

 1#if _MSC_VER
 2#define PlaceHolder std::_Ph
 3#else
 4#define PlaceHolder std::_Placeholder
 5#endif
 6
 7template<int N, int...I>
 8struct MakeSeqs : MakeSeqs<N - 1, N - 1, I...> {};
 9
10template<int...I>
11struct MakeSeqs<1, I...>
12{
13	template<typename T, typename R, typename...Args>
14	static auto bind(T* obj, R(T::*_Func)(Args...)) -> decltype(std::bind(_Func, obj, PlaceHolder<I>{}...))
15	{
16		return std::bind(_Func, obj, PlaceHolder<I>{}...);
17	}
18};
19
20template <typename T, typename R, typename...Args>
21auto Bind(T* t, R(T::*f)(Args...)) -> decltype(MakeSeqs<sizeof...(Args)+1>::bind(t, f))
22{
23	return MakeSeqs<sizeof...(Args)+1>::bind(t, f);
24}
25
26template <typename T, typename R, typename...Args>
27auto Bind(R(T::*f)(Args...), T* t) -> decltype(MakeSeqs<sizeof...(Args)+1>::bind(t, f))
28{
29	return MakeSeqs<sizeof...(Args)+1>::bind(t, f);
30}

由于C++11的auto不能完全自动推导类型,所以auto返回类型的函数后面需要写decltype。如果使用C++ 14则更简洁:

 1#if _MSC_VER
 2#define PlaceHolder std::_Ph
 3#else
 4#define PlaceHolder std::_Placeholder
 5#endif
 6
 7template<int N, int...I>
 8struct MakeSeqs : MakeSeqs<N - 1, N - 1, I...> {};
 9
10template<int...I>
11struct MakeSeqs<1, I...>
12{
13	template<class T, class _Fx>
14	static auto bind(T&& obj, _Fx&& _Func)
15	{
16		return std::bind(std::forward<_Fx>(_Func), std::forward<T>(obj), PlaceHolder<I>{}...);
17	}
18};
19
20template <class T, class R, typename...Args>
21auto Bind(T* t, R(T::*f)(Args...))
22{
23	return MakeSeqs<sizeof...(Args)+1>::bind(t, f);
24}
25
26template <class T, class R, typename...Args>
27auto Bind(R(T::*f)(Args...), T* t)
28{
29	return MakeSeqs<sizeof...(Args)+1>::bind(t, f);
30}

有了这段辅助代码,前面的示例代码的main函数就可以改写成:

1int main()
2{
3	CTest t;
4	auto f1 = Bind(&CTest::foo1, &t);
5	auto f2 = Bind(&CTest::foo2, &t);
6	return 0;
7}

是不是感觉清爽多了? 以上代码在VS2015以及GCC4.9.3以上版本编译通过,GCC需要使用-std=c++11或者-std=c++14参数进行编译。

祝好!