C++11 std::bind関数バインド占拠パラメータstd::placeholders::1……

3102 ワード

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;
}

さわやかになったのではないでしょうか.以上のコードはVS 2015およびGCC 4にある.9.3以上のバージョンのコンパイルにより、GCCは-std=c++11または-std=c++14パラメータを使用してコンパイルする必要があります.
おめでとうございます.