裹一层重载的成员函数指针

Using variable-length parameter templates and lambda (or using generic lambda) to wrap overloaded member function pointers for convenient usage (like bind binding or other places that require overloaded member function pointers). For more introduction on member function pointers, please see my other article: Pointers to Class Members in C++ Are Not Pointers.

Note: The code uses some C++14 features, and you need to compile with the -std=c++14 parameter.

Currently, there is a class with several overloaded member functions as follows:

1
2
3
4
5
6
7
8
9
struct A
{
void func(int x){
cout<<"A::func(int)"<<endl;
}
void func(float x){
cout<<"A::func(float)"<<endl;
}
};

Typically, we can obtain member function pointers using the following method:

1
2
3
4
5
A aobj;
void(A::* AfuncInt)(int)=&A::func;
(aobj.*AfuncInt)(11);// call A::func(int)
void(A::* AfuncFloat)(float)=&A::func;
(aobj.*AfuncFloat)(11.11);// call A::func(float)

Since the type system cannot express the candidate set, if we want to bind to this class’s member function func, we can only manually specify the overloaded parameters:

1
2
auto x=bind((void(A::*)(float))&A::func,aobj,_1);
auto y=bind((void(A::*)(int))&A::func,aobj,_1);

This is too tedious, so we can use a generic lambda to wrap it:

1
2
3
4
5
6
7
8
auto genLambda=[](auto argType)->auto{
return (void(A::*)(decltype(argType)))&A::func;
};
// direct call
(aobj.*(genLambda(int{})))(11);
// bind
auto AfunInt=bind(genLambda(int{}),aobj,_1);
Afun(11);//call A::func(int)

However, it still feels a bit cumbersome, so let’s make it an auxiliary function where the first template parameter accepts the class type and the second template parameter receives the function’s parameter type:

1
2
3
4
5
6
7
template<typename T,typename U>
auto AfuncArgType(void){
auto argType=[](void)->auto{
return (void(T::*)(U))&A::func;
};
return argType();
}

Then we can call it like this:

1
2
3
4
5
6
7
// direct call
(aobj,*(AfuncArgType<A,int>()))(10);//call A::func(int)
// bind
auto AfuncInt=bind(AfuncArgType<A,int>(),aobj,_1);
AfuncInt(11);// call A::func(int);
auto AfuncFloat=bind(AfuncArgType<A,float>(),aobj,_1);
AfuncFloat(11.11);// call A::func(float)

Originally, I planned to wrap the bind as well, but using _1_n in the placeholders namespace becomes inconvenient to specify with different numbers of overloaded function parameters.

Moreover, the code above has a limitation: it can only specify a single parameter function. If I overload multiple parameter versions, the above code won’t work.

However, we can use variable-length parameter templates to support multiple template parameters. Since we must specify at least the class type, there need to be two template parameters, T as the class type and Args as the parameter types of the function members of class A:

1
2
3
4
5
6
7
template<typename T,typename... Args>
auto AfuncArgType(void){
auto argType=[](void)->auto{
return (void(T::*)(Args...))&T::func;
};
return argType();
}

This way, we can bind multiple parameters. Suppose we have overloaded two versions with multiple parameters on top of the previous class:

1
2
3
4
5
6
7
8
9
10
struct A
{
// ....
void func(int x,float y){
cout<<"func(int,float)"<<endl;
}
void func(int x,int y,bool z){
cout<<"func(int,int,bool)"<<endl;
}
};

We can use the variable template parameters version above:

1
2
3
4
auto AfuncIntFloat=bind(AfuncArgType<A,int,float>(),aobj,_1,_2);
AfuncIntFloat(10,11.11); // call A::func(int,float)
auto AfuncIntFloatBool=bind(AfuncArgType<A,int,int,bool>(),aobj,_1,_2,_3);
AfuncIntFloatBool(10,11.11,true); // call A::func(int,float,bool)

Compare to the code if done directly:

1
2
3
4
5
6
auto a=bind((void(A::*)(float))&A::func,aobj,_1);
a(11);
auto b=bind((void(A::*)(int,float))&A::func,aobj,_1,_2);
b(11,12.11);
auto c=bind((void(A::*)(int,int,bool))&A::func,aobj,_1,_2,_3);
c(11,12.11,true);
The article is finished. If you have any questions, please comment and communicate.

Scan the QR code on WeChat and follow me.

Title:裹一层重载的成员函数指针
Author:LIPENGZHA
Publish Date:2016/12/31 04:02
Update Date:2017/05/15 16:27
World Count:1.6k Words
Link:https://en.imzlp.com/posts/19740/
License: CC BY-NC-SA 4.0
Reprinting of the full article is prohibited.
Your donation will encourage me to keep creating!