C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Must second bind2nd parameter be constant for loop?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Rex Kerr
Guest





PostPosted: Sat Dec 09, 2006 10:10 am    Post subject: Must second bind2nd parameter be constant for loop? Reply with quote



I'm trying to compare two vectors to ensure that their values are equal
within a tollerance (easy, std::equal with a binary predicate), but my
definition of equal also allows for a certain number of values to lie
outside of the tollerance, so I want something like std::count_if that
takes two ranges and passes them to a binary op.

So, I've tried using bind2nd and using a post-incremented iterator as
the second parameter (which doesn't work), but then I also realized
that I'm making an assumption that the count_if algorithm works
sequentially from begin to end, which it may not.

So, how would I do such a thing using standard algorithms?

Here's what I have that doesn't work:

namespace
{
template <class T>
struct OutsideTollerance : public std::binary_function<T, T, T>
{
T operator() (T v1, T v2) const
{
return std::abs(v2 - v1) >= 2; // hardcoded for example
}
};
}

std::size_t num_mismatched = std::count_if( v1.begin(), v1.end(),
std::bind2nd(OutsideTollerance<BYTE>(), *(v2it++)) );

(variable names changed to protect the innocent)

Thanks!


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Guest






PostPosted: Sun Dec 10, 2006 9:29 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote



I would try this, although I understand you might not like using
const_cast.

struct EuqalWithTollerance : public std::binary_function<double,
double, bool>
{
EuqalWithTollerance( double tol, int maxOutOfRange ) :
tol_(tol), mOut_(maxOutOfRange), nOut_(0) {};
bool operator() (double v1, double v2) const
{
return (fabs(v2 - v1) < tol_)? true : (++const_cast<int&>(nOut_) <
mOut_);
}
double tol_;
int nOut_;
int mOut_;
};

std::equal( v1.begin(), v1.end(), v2.begin(), EuqalWithTollerance(
1e-4, 3 ) );

Rex Kerr wrote:
Quote:
I'm trying to compare two vectors to ensure that their values are equal
within a tollerance (easy, std::equal with a binary predicate), but my
definition of equal also allows for a certain number of values to lie
outside of the tollerance, so I want something like std::count_if that
takes two ranges and passes them to a binary op.

So, I've tried using bind2nd and using a post-incremented iterator as
the second parameter (which doesn't work), but then I also realized
that I'm making an assumption that the count_if algorithm works
sequentially from begin to end, which it may not.

So, how would I do such a thing using standard algorithms?

Here's what I have that doesn't work:

namespace
{
template <class T
struct OutsideTollerance : public std::binary_function<T, T, T
{
T operator() (T v1, T v2) const
{
return std::abs(v2 - v1) >= 2; // hardcoded for example
}
};
}

std::size_t num_mismatched = std::count_if( v1.begin(), v1.end(),
std::bind2nd(OutsideTollerance<BYTE>(), *(v2it++)) );

(variable names changed to protect the innocent)

Thanks!


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Mathias Gaunard
Guest





PostPosted: Sun Dec 10, 2006 10:10 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote



Rex Kerr wrote:

Quote:
Here's what I have that doesn't work:

namespace
{
template <class T
struct OutsideTollerance : public std::binary_function<T, T, T
{
T operator() (T v1, T v2) const
{
return std::abs(v2 - v1) >= 2; // hardcoded for example
}
};
}

std::size_t num_mismatched = std::count_if( v1.begin(), v1.end(),
std::bind2nd(OutsideTollerance<BYTE>(), *(v2it++)) );


What's `v2it'?


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Pete Becker
Guest





PostPosted: Sun Dec 10, 2006 10:10 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

Rex Kerr wrote:
Quote:
I'm trying to compare two vectors to ensure that their values are equal
within a tollerance (easy, std::equal with a binary predicate), but my
definition of equal also allows for a certain number of values to lie
outside of the tollerance, so I want something like std::count_if that
takes two ranges and passes them to a binary op.


count_if won't help here, because it doesn't take two ranges.

If you insist on using algorithms from the standard library, I think
you've got a two step process. First, use transform to walk through the
two ranges and write out a sequence giving the result of each comparison
of pairs of values. Then walk through that sequence and count the number
of values that are out of tolerance.

If you want to roll your own algorithm, it's straightforward:

template <class InIt1, class InIt2>
int out_of_tolerance(InIt1 first1, InIt1 last1, InIt2 first2)
{
int count = 0;
while (first1 != last1)
if (compare(*first1++, *first2++))
++count;
return count;
}

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carlos Moreno
Guest





PostPosted: Sun Dec 10, 2006 10:10 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

Rex Kerr wrote:

Quote:
So, I've tried using bind2nd and using a post-incremented iterator as
the second parameter (which doesn't work), but then I also realized
that I'm making an assumption that the count_if algorithm works
sequentially from begin to end, which it may not.

What?? How exactly would it not go sequentially from begin to end???
That is precisely how it's described in its documented functionality.

Quote:
std::size_t num_mismatched = std::count_if( v1.begin(), v1.end(),
std::bind2nd(OutsideTollerance<BYTE>(), *(v2it++)) );

There's an clear detail that you have to realize: count_if is a
function; and bind2nd is one of its parameters!! The value of
the parameter is evaluated and passed to the function --- how
many times is the parameter evaluated? Well, the function is
called *once*, so the parameter is evaluated that same one time,
then passed to the function.

I guess you would solve it with your own custom function object
that keeps track (via a data member) of how many elements have
fallen outside tolerance --- as soon as you exceed the limit,
then the functor starts returning false, at which point std::equal
will immediately return false.

HTH,

Carlos

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Seungbeom Kim
Guest





PostPosted: Mon Dec 11, 2006 7:46 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

fcannizzo.mifft2001 (AT) london (DOT) edu wrote:
Quote:
I would try this, although I understand you might not like using
const_cast.

struct EuqalWithTollerance : public std::binary_function<double, double,
bool
{
EuqalWithTollerance( double tol, int maxOutOfRange ) :
tol_(tol), mOut_(maxOutOfRange), nOut_(0) {};
bool operator() (double v1, double v2) const
{
return (fabs(v2 - v1) < tol_)? true : (++const_cast<int&>(nOut_)
mOut_);
}
double tol_;
int nOut_;
int mOut_;
};

std::equal( v1.begin(), v1.end(), v2.begin(), EuqalWithTollerance( 1e-4,
3 ) );


It's a nice idea, but why do you need const_cast? You can make
operator() a non-const member function and get rid of const_cast.

And it turns that you can save an extra variable: :)

template <typename T>
class EqualWithTolerance
: public std::binary_function<T, T, bool>
{
public:
EqualWithTolerance(T tol, int max_out_tol)
: tol_(tol), n_(max_out_tol) { }

bool operator()(double v1, double v2)
{
return (std::abs(v2 - v1) < tol_) || (--n_ >= 0);
}

private:
T tol_;
int n_;
};

bool equal = std::equal(v1.begin(), v1.end(), v2.begin(),
EqualWithTolerance(1e-4, 3));

--
Seungbeom Kim

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Matthew T. Staebler
Guest





PostPosted: Tue Dec 12, 2006 7:52 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

Carlos Moreno wrote:
Quote:
James Kanze wrote:
Note too that the predicate must be copiable, and the algorithm
can copy it as many times and whenever it wants.

So, you're suggesting that the implementation could be recursive?
Wink

I would hate to put words into James's mouth, but I assume that he was
cautioning someone using algorithms such as count_if and equal from
relying on predicates that store values that change as elements of the
range are visited. In the EqualWithTolerance class defined above,
there is an int nOut_ member whose value should be based upon the
results of previous visits to other elements of the range. However, it
is not guaranteed that the EqualWithTolerance object that visits one
element will be the same as the EqualWithTolerance object that visits
another element, as the implementation of the algorithm has the
flexibility to copy the predicate object as it sees fit. It would be a
perfectly legal implementation of the algorithm to create a unique copy
of the passed predicate object for every element of the range. Using
such an implementation with the EqualWithTolerance class as a predicate
would mean that every element would be visited with an
EqualWithTolerance object whose nOut_ member had a value of 0.

While it is probably unlikely (although still legal) for an
implementation of count_if and equal to copy the predicate object in
such a fashion, it is much more likely for other algorithms such a
find_if to copy the predicate object. If one is in the habit of
ignoring the possibility for unlikely algorithms such as count_if, it
is much easier to forget about the possibility for likely algorithms
such as find_if.

One fairly simple solution to this problem is to use a reference for
the mutable values in your predicate object. Changing the nOut_ member
in EqualWithTolerance from an int to an int& and supplying an int& to
the constructor of EqualWithTolerance will resolve the issue.

Matthew T. Staebler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Maxim Yegorushkin
Guest





PostPosted: Wed Dec 13, 2006 5:42 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

Michiel.Salters (AT) tomtom (DOT) com wrote:
Quote:
Rex Kerr wrote:
I'm trying to compare two vectors to ensure that their values are equal
within a tollerance (easy, std::equal with a binary predicate),
Here's what I have that doesn't work:

namespace
{
template <class T
struct OutsideTollerance : public std::binary_function<T, T, T
{
T operator() (T v1, T v2) const
{
return std::abs(v2 - v1) >= 2; // hardcoded for example
}
};
}

std::size_t num_mismatched = std::count_if( v1.begin(), v1.end(),
std::bind2nd(OutsideTollerance<BYTE>(), *(v2it++)) );

(variable names changed to protect the innocent)

Let's guess - originally it was OutsideTolerance ? ;)

Seriously - when using the STL, try to write proper functors. For any
kind of
"equal" operation, make sure that equal(a,b) and equal(a,c) implies
equal(b,c).
OutsideTolerance is not such an equal function. Now, your requirements
will
say you need OutsideTolerance to behave like this. That's life, it just
means
that using the STL here won't be trivial.

Does count_if require a functor with properties of equal()? I guess,
it's an unary functor in question...


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carlos Moreno
Guest





PostPosted: Wed Dec 13, 2006 5:43 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

James Kanze wrote:

Quote:
What?? How exactly would it not go sequentially from begin to end???

By visiting the elements in some other order.

I was going to start my reply with a "James, why are you being silly?"
:-)

What's silly about [...]

Notice the --- and this time I'll emphasize it --- *I was going to*
start with .... :-)

I interpreted the original comment of going sequentially from begin
to end in a different way --- notice that the problem in the OP was
that he was somehow magically expecting his parameter to be re-
evaluated for each iteration *inside the algorithm*, and somewhat
he associated that idea with that of "iterating sequentially from
begin to end" --- which, of course, is the obvious and straightforward
way of implementing count_if.

That's why your answer of "by visiting the elements in some other
order" sounded to me like you were just nitpicking with something
silly that didn't even make sense --- it, of course, made sense as
soon as I read the rest of your message (perhaps I should have
added that detail after the initial comment Smile)

Quote:
That is precisely how it's described in its documented functionality.

Where is that documented.

I was expecting to see in the preconditions that it accepts an
input forward iterator

What does the type of iterator have to do with anything?

It has to do with my confused brain :-)

I was overlooking the fact that by putting lower requirements
in the parameters you're *not* preventing implementations that
take advantage of other iterators that meet *and exceed* those
requirements; IOW, my confusion was that I was expecting that
if the expected iterator is an input *forward* iterator, *the*
implementation must be such that it will work with that form
of iterator (and therefore, it would *have to* visit the
elements sequentially *starting at begin*) --- what it really
requires is that *at least one* available implementation does,
as you pointed out.

Quote:
So, you're suggesting that the implementation could be recursive?
;-)

There's nothing to forbid it.

The rest was, of course, mostly kidding :-)


Quote:
int count_if (Iterator begin, Iterator end, Function predicate)
{
if (begin == end)
{
return 0;
}
else
{
return count_if (++Iterator(begin), end)
+ (pred(*begin) ? 1 : 0);
}
}


You'd have to use meta-programming techniques to specialize the
algorithm---your code here won't work for InputIterators. Other
than that, it's perfectly legal.

I see that you also overlooked the couple of details that I
overlooked --- the call to count_if should receive the parameter
predicate, and pred(*begin) should have been predicate(*begin).

But putting that aside, and at the risk of continuing to make a
fool of myself, I have to ask: why doesn't the above work for
input iterators?? They support copy-construction, and they
most definitely support pre-increment (which necessarily
returns a reference to the incremented value).

So, what am I missing now?

Carlos
--

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Matthew T. Staebler
Guest





PostPosted: Wed Dec 13, 2006 10:10 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

Carlos Moreno wrote:
Quote:
int count_if (Iterator begin, Iterator end, Function predicate)
{
if (begin == end)
{
return 0;
}
else
{
return count_if (++Iterator(begin), end)
+ (pred(*begin) ? 1 : 0);
}
}


James Kanze wrote:
You'd have to use meta-programming techniques to specialize the
algorithm---your code here won't work for InputIterators. Other
than that, it's perfectly legal.

I see that you also overlooked the couple of details that I
overlooked --- the call to count_if should receive the parameter
predicate, and pred(*begin) should have been predicate(*begin).

But putting that aside, and at the risk of continuing to make a
fool of myself, I have to ask: why doesn't the above work for
input iterators?? They support copy-construction, and they
most definitely support pre-increment (which necessarily
returns a reference to the incremented value).

So, what am I missing now?

Your implementation of count_if relies on an order of evalution that is
not guaranteed by the standard. Specifically, the dereference of the
begin iterator must be evaluated before the increment of the iterator
copied from the begin iterator. InputIterators do not guarantee that
any copies of the iterator can be dereferenced after the iterator has
been incremented. There is no way to safely traverse a range using
InputIterators in a manner other than sequentially.

-----
Matthew T. Staebler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Carlos Moreno
Guest





PostPosted: Thu Dec 14, 2006 5:48 am    Post subject: Re: Must second bind2nd parameter be constant for loop? Reply with quote

James Kanze wrote:

Quote:
But putting that aside, and at the risk of continuing to make a
fool of myself, I have to ask: why doesn't the above work for
input iterators?? They support copy-construction, and they
most definitely support pre-increment (which necessarily
returns a reference to the incremented value).

So, what am I missing now?

[...]
Note that last post-condition. The ++ on the *copy* of begin
means that begin itself is no longer required to be
dereferenceable, which means that (*begin) is illegal. And
since order of evaluation isn't specified, a compiler could do
the incrementation before the dereferencing.

*sigh* ... Of course, after seeing the explanation, I can only
say DUH!! How could I forget about the (rather obvious) possibility
of calling count_if as:

count_if (istream_iterator<int>(file), istream_iterator<int>(), ...)


Thanks (and thanks Matthew) for having the patience to remind me
this detail!

Cheers,

Carlos
--

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.