Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ std::mem_fn with overloaded member function

When compiling the following code, Visual Studio reports:

\main.cpp(21): error C2664: 'std::_Call_wrapper<std::_Callable_pmd<int ClassA::* const ,_Arg0,false>,false> std::mem_fn<void,ClassA>(int ClassA::* const )' : cannot convert argument 1 from 'overloaded-function' to 'int ClassA::* const '
    1>          with
    1>          [
    1>              _Arg0=ClassA
    1>          ]
    1>          Context does not allow for disambiguation of overloaded function

Why is the compiler confused when creating mem_fptr1? But some how mem_fptr2 is ok when I specify the types.

Can I create member function pointer to an overloaded member function that takes no argument?

class ClassA
{
public:
    void memberfunction()
    {
        std::cout <<"Invoking ClassA::memberfunction without argument" << std::endl;
    }

    void memberfunction(int arg)
    {
        std::cout << "Invoking ClassA::memberfunction with integer " << arg << std::endl;
    }
};

int main()
{
    auto mem_fptr1 = std::mem_fn<void, ClassA>(&ClassA::memberfunction);
    auto mem_fptr2 = std::mem_fn<void, ClassA, int>(&ClassA::memberfunction);

    mem_fptr1(ClassA());
    mem_fptr2(ClassA(), 3);
}
like image 446
Frank Liu Avatar asked Sep 10 '14 12:09

Frank Liu


1 Answers

The template overloads taking a variadic list of argument types were introduced in C++11 but removed in C++14 as defect #2048. The way to specify a particular overload is to specify a function type as the first template argument (the second template argument, the class type, can be omitted as it can be deduced):

auto mem_fptr1 = std::mem_fn<void()>(&ClassA::memberfunction);
auto mem_fptr2 = std::mem_fn<void(int)>(&ClassA::memberfunction);

The function type R is then composed with the class type T as R T::* to give the member function type. This also allows forming a std::mem_fn to a data member (where R is a non-function type).

Note that your code (for mem_fptr2) does not work in C++14 where the template overloads taking a variadic list of argument types are removed; the above code will work in both versions of the Standard.

An alternative is to perform a member function cast; in this case you do not need to specify template arguments to mem_fn:

auto mem_fptr1 = std::mem_fn(
    static_cast<void (ClassA::*)()>(&ClassA::memberfunction));
auto mem_fptr2 = std::mem_fn(
    static_cast<void (ClassA::*)(int)>(&ClassA::memberfunction));
like image 76
ecatmur Avatar answered Sep 20 '22 02:09

ecatmur