Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

tr1::mem_fn and members with default arguments

Tags:

c++

tr1

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...

like image 398
Nicola Bonelli Avatar asked Mar 02 '23 04:03

Nicola Bonelli


2 Answers

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).

like image 178
coppro Avatar answered Mar 10 '23 21:03

coppro


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)

like image 26
Johannes Schaub - litb Avatar answered Mar 10 '23 21:03

Johannes Schaub - litb