C++ 11 std::bind函数绑定如何省略占位参数std::placeholders::_1……
我们在使用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参数进行编译。
祝好!
- 原文作者:Witton
- 原文链接:https://wittonbell.github.io/posts/2019/2019-08-02-C++-11-stdbind函数绑定如何省略占位参数stdplaceholders_1/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。