C++ 11 std::bind函数绑定如何省略占位参数std::placeholders::_1……

我们在使用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参数进行编译。

祝好!

你可能感兴趣的:(C/C++/VC/MFC)