tags:

views:

639

answers:

2

I have class with a member function that takes a default argument.

struct Class
{
    void member(int n = 0)
    {}
};

By means of std::tr1::mem_fn I can invoke it:

Class object;

std::tr1::mem_fn(&Class::member)(object,10);

That said, if I want to invoke the callable member on the object with the default argument, what's the correct syntax?

std::tr1::mem_fn(&Class::member)(object); // This does not work

g++ complains with the following error:

test.cc:17: error: no match for call to ‘(std::tr1::_Mem_fn<void (Class::*)(int)>) (Class&)’
/usr/include/c++/4.3/tr1_impl/functional:551: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]
/usr/include/c++/4.3/tr1_impl/functional:556: note:                 _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = void, _Class = Class, _ArgTypes = int]

Still, the I have the same problem when Class::member is overloaded by members that takes different arguments...

+3  A: 

The reason is that any default arguments do not change the function type of a function.

mem_fn has no way to know the function only requires 1 argument, or that the functions' second argument is optional, since all the knowledge it gets is given to it by the type of &Class::member (which stays void(Class::*)(int)) . It therefor requires an integer as the second argument.

If you want to pass the address of a member function overloaded, you have to cast to the right member function pointer type:

static_cast<void(Class::*)()>(&Class::member) instead of just &Class::member, so the compiler has a context to figure out which address is to be taken.

Edit: coppro has a nicer solution how to provide context: std::tr1::mem_fn<void()>(&Class::member)

Johannes Schaub - litb
+5  A: 

Default functions are bound at call time, but can't be bound into any sort of wrapper implicitly, because of the way they are implemented. When you pass &Class::member, mem_fn only sees a void (Class::*)(int), and can't see the default argument. Using tr1::bind, you can bind the default argument explictly: std::tr1::bind(&Class::member, 0) or you can use it as you would mem_fn, but you can't do both in one object. You would have to write your own wrapper class for that.

As for overloads, you will have to explicitly specify the template arguments for mem_fn so the right function pointer is picked as in mem_fn<void(int)>(&Class::member).

coppro