Question

I am having trouble figuring out mem_fun_ref. I have to admit, I usually use functors for this kind of thing, since they can be inlined for speed and profit. However, this code is not going to be a bottleneck and so I wanted to try this thing.

Here is an example of what I want to do. I know there are other ways to do it. I don't want to use copy, I don't want to use range member functions, I don't want to use a back_inserter. I specifically want to use mem_fun_ref. This is just a simple example, the real case is much more complicated. That said, I really don't know why this is wrong, but I am not familiar with mem_fun_ref or mem_fun.

Here's what I want to work:

#include <list>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

int main()
{
    list<int> a;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);
    vector<int> b;

    // should work like magic!
    for_each(a.begin(), a.end(), bind1st(mem_fun_ref(&vector<int>::push_back), b));
}

But I get 3 errors:

1>c:\program files\microsoft visual studio 9.0\vc\include\functional(276) : error C2529: '_Right' : reference to reference is illegal
1>c:\program files\microsoft visual studio 9.0\vc\include\functional(281) : error C2529: '_Right' : reference to reference is illegal
1>c:\program files\microsoft visual studio 9.0\vc\include\functional(282) : error C2535: 'void std::binder1st<_Fn2>::operator ()(const int &(&)) const' : member function already defined or declared
1>        with
1>        [
1>            _Fn2=std::mem_fun1_ref_t<void,std::vector<int>,const int &>
1>        ]
1>        c:\program files\microsoft visual studio 9.0\vc\include\functional(276) : see declaration of 'std::binder1st<_Fn2>::operator ()'
1>        with
1>        [
1>            _Fn2=std::mem_fun1_ref_t<void,std::vector<int>,const int &>
1>        ]

reference to reference is illegal makes me think that the function needs to take a parameter by value. But of course, this is not possible to change in vector, and it's not possible to change it in my code either. Is there a simple change to get this to work? I need a solution that's a 1-liner.

Was it helpful?

Solution

Just use bind. The mem_fun versions are too difficult.

for_each(a.begin(), a.end(),
  boost::bind(&vector<int>::push_back, boost::ref(b), _1));

Another way that doesn't require the use of ref is to pass a pointer to the vector to be modified:

for_each(a.begin(), a.end(),
  boost::bind(&vector<int>::push_back, &b, _1));

OTHER TIPS

This problem was explained in "Exceptional C++ Style" by Herb Sutter, page 28-30. One probably cannot safely create a pointer to a vector<int>::push_back method as one needs to be sure of exact signature of the member function, which may not be obvious even for vector<int>::push_back in Standard Library. This is because (in Standard Library):

  1. A member function signature with default parameters might be replaced by "two or more member function signatures with equivalent behavior.
  2. A member function signature might have additional defaulted parameters.

In the end, Herb Sutter advised that

  1. Use mem_fun, Just Not with the Standard Library
  2. Use Pointers to Member Functions, Just Not with the Standard Library

I know that you've said you don't want to use back_inserter, probably because you've given just simplified example code.

For anyone else wondering how to do exactly what you're trying to do, and happy to use it, use back_inserter:

std::copy(a.begin(), a.end(), std::back_inserter(b));

That said, there's always other_mem_fun, which I cooked up before I knew about boost. This might fit.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top