non-const for_each usage

C

Capstar

Hi NG,

I have a question on std::for_each. I try to use this in combination
with std::bind2nd to call a method of all functions in a container
(std::set or std::map) and pass that method the second argument of
std::bind2nd.
But for some reason the compiler wants met ot have all const objects,
which obviously doesn't work when the method is non-const.
example:

/** test.cpp **/
#include <set>
#include <algorithm>

class myInt
{
int i_;
public:
myInt(int i): i_(i) {}
int val() const { return i_; }
void setVal(int i) { i_ = i; }
bool operator<(const myInt & rhs) const { return i_ < rhs.i_; }
};

struct intAdder : public std::binary_function<myInt,int,void>
{
void operator()(myInt & ref, int x) const
{
ref.setVal(ref.val() + x);
}
};

int main()
{
std::set<myInt> s;

s.insert( myInt( 3 ) );
s.insert( myInt( 5 ) );

std::for_each(s.begin(), s.end(), std::bind2nd(intAdder(), 2));

return 0;
}

The interesting thing is that this code does compile with
cl /Zi /GX /GR test.cpp (win32 13.10.3077)

but doesn't compile with
g++ -W -Wall test.cpp (gcc 3.2.3)

Mark
 
R

Robbie Hatley

Capstar said:
Hi NG,

I have a question on std::for_each. I try to use this in combination
with std::bind2nd to call a method of all functions in a container
(std::set or std::map) and pass that method the second argument of
std::bind2nd.
But for some reason the compiler wants met ot have all const objects,
which obviously doesn't work when the method is non-const.
example:

/** test.cpp **/
#include <set>
#include <algorithm>

class myInt
{
int i_;
public:
myInt(int i): i_(i) {}
int val() const { return i_; }
void setVal(int i) { i_ = i; }
bool operator<(const myInt & rhs) const { return i_ < rhs.i_; }
};

struct intAdder : public std::binary_function<myInt,int,void>
{
void operator()(myInt & ref, int x) const
{
ref.setVal(ref.val() + x);
}
};

int main()
{
std::set<myInt> s;

s.insert( myInt( 3 ) );
s.insert( myInt( 5 ) );

std::for_each(s.begin(), s.end(), std::bind2nd(intAdder(), 2));

return 0;
}

The interesting thing is that this code does compile with
cl /Zi /GX /GR test.cpp (win32 13.10.3077)

but doesn't compile with
g++ -W -Wall test.cpp (gcc 3.2.3)

Mark

Upon looking at page 519 of Stroustrup's "C++ Programming Language"
I see that the application operator of class "binder2nd" takes a
constant ref argument. Hence the embedded "binary operation"
cannot change its left argument.

Stroustrup implies that bind2nd and binder2nd are intended for
manufacturing predicates which return booleans and don't alter
their arguments.

Another problem is, I don't think std::set has an asignment
operator for elements. You're supposed to use insert, erase,
etc., instead of "=". Which is why for_each sees the elements
of your set as being "const".

For one thing, std::set has a rule that no two values can
be equal. A "=" operator would allow the user to contravene
that rule, which is why there's "insert" and "erase", so that
std::set can enforce it's "no duplicates" rule.

To illustrate, if you changed your set to a list, and also
changed the bind2nd to a functor, the altered program compiles
and runs fine:

#include <set>
#include <algorithm>
#include <list>

class myInt
{
int i_;
public:
myInt(int i): i_(i) {}
int val() const { return i_; }
void setVal(int i) { i_ = i; }
bool operator<(const myInt & rhs) const { return i_ < rhs.i_; }
};

struct intAdder
{
int Right;
intAdder(int R) : Right(R) {}
void operator()(myInt & Left) {Left.setVal(Left.val() + Right);}
};

int main()
{
std::list<myInt> s;

s.push_back( myInt( 3 ) );
s.push_back( myInt( 5 ) );

std::for_each(s.begin(), s.end(), intAdder(2));

return 0;
}


So your problems really had nothing to do with for_each, but
rather with your usage of bind2nd and std::set.

If you really need a std::set, I don't think you can use
for_each (or anthing else, for that matter) to alter the elements.
I believe the elements are unalterable. You can replace them
by "erase(5); insert(7);". But you can't do THIS:


#include <set>
int main(void)
{
std::set<int> s;
s.insert( 3 );
s.insert( 5 );
(*(s.begin())) = 9; // ILLEGAL
return 0;
}

Compiler error reads: "Error: asignment to read-only location!"

Sets just don't work that way.

--
Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,020
Latest member
GenesisGai

Latest Threads

Top