3

Firstly, I had a snippet as following:

struct D
{

  int sum;

  D():sum(0){accum();}

  void incre(int arg){sum+=arg;}

  void accum()
  {
    int arr[]={1,2,3,4,5};

    std::for_each(arr,arr+ sizeof(arr)/sizeof(int),
                  std::bind1st(std::mem_fun(&D::incre),this));

    cout << sum <<endl;
  }
};

int main()
{
  D();
}

It compiled properly.But after my changing the member function incre to

void incre(int &  arg){sum+=arg;}

it produced errors, like

typename _Operation::result_type std::binder1st<_Operation>::operator()
    (typename _Operation::second_argument_type&) const [with _Operation = 
    std::mem_fun1_t<void, D, int&>]’ cannot be overloaded

Do you have any ideas about what is going on? I'll appreciate any help.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
Wang HongQin
  • 303
  • 3
  • 10

2 Answers2

5

What is going on is that bind1st and mem_fun do not work with references on all platforms.

You can use it with boost::bind

std::for_each( arr, arr + sizeof(arr)/sizeof(int), 
   boost::bind( &D::incre, this, _1 ) );

and it would seem GNU have decided the above is a good enough workaround to mark the bug as "won't fix".

In your case you could pass in by value. You can also happily pass pointers into these functions.

What you are doing should work, by the way.

Passing by value might not fix it either because you are calling a non-const member function. There was an issue also about non-const member functions.

Your other alternative of course is to use std::accumulate rather than std::for_each, which is suitable for this particular case where you are running through your collection generating something. The way I generally prefer to use accumulate is:

Result r;
Result* binaryfunc( Result*, T value ); // returns the same pointer passed in
std::accumulate( coll.begin(), coll.end(), binaryfunc, &r );

which avoids copying the "Result" on every iteration. There is no need to use bind1st or mem_fun here so no issue either if you are passing in value by reference.

CashCow
  • 30,981
  • 5
  • 61
  • 92
  • but it's the same after changing it to void incre(const int & arg){sum+=arg;} (how can i insert newlines in comments?) – Wang HongQin Mar 18 '11 at 09:23
  • I could be wrong about this, but I believe that mem_fun doesn't work with any type of references, even const references. If I'm wrong, please let me know and I can remove the downvote. – templatetypedef Mar 18 '11 at 09:37
  • The non-const member function and no-references are two separate issues, and I potentially got them confused but then so did they on gnu so I'm in good company... – CashCow Mar 18 '11 at 10:30
4

The problem is that internally, mem_fun tries to set as its argument type a const reference to the argument type of the member function. If you make then function take in a reference, then it tries to create a reference to a reference, which is illegal in C++. This is a known defect in the library and is being remedied by the new bind function that will appear in C++0x.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • thank you for helping. Note that you said 'then it tries to create a reference to a reference, which is illegal in C++.' I am not familiar with this rule, but after my testing : 'int a; int &b=a;int &c=a', it works well. so did i misunderstand or what? – Wang HongQin Mar 18 '11 at 09:49
  • By a reference to a reference I meant something like an int & &, that is, a type that's a reference type whose underlying type is also a reference. You can make pointers to pointers, as in int** x, but not references to references. Does that make sense? – templatetypedef Mar 18 '11 at 10:01
  • yeah,i got it. your explanation is very explicit.thank you very much. I'm just sorry i've no enough reputation to vote your answer up : p – Wang HongQin Mar 18 '11 at 10:15