By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,814 Members | 1,671 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,814 IT Pros & Developers. It's quick & easy.

non-const for_each usage

P: n/a
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
Sep 20 '05 #1
Share this Question
Share on Google+
1 Reply


P: n/a
"Capstar" wrote:
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
Sep 20 '05 #2

This discussion thread is closed

Replies have been disabled for this discussion.