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

std::find_if, std::logical_or and short evaluation

P: n/a
Hi,

when the following code is executed

bool Test1();
bool Test2();

....
if (Test1() || Test2()) { ... }
....

Test2 is executed only if Test1 returns false.

I am trying to create a predicate for find_if with the same behaviour:

find_if(iterBegin,iterEnd, Test1 || Test2)
For do this I have modificated the boost::compose_f_gx_hx template in
this way:

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

/* class for the compose_gx_op_hx adapter
*/
template <class OP1, class OP2, class OP3>
class compose_gx_op_hx_t
: public std::unary_function<typename OP2::argument_type,
typename OP1::result_type>
{
private:
OP1 op1; // process: op2(x) op1 op3(x)
OP2 op2;
OP3 op3;
public:
// constructor
compose_gx_op_hx_t (const OP1& o1, const OP2& o2, const OP3& o3)
: op1(o1), op2(o2), op3(o3) {
}

// function call
typename OP1::result_type
operator()(const typename OP2::argument_type& x) const {
return op2(x) || op3(x);
// return op1(op2(x),op3(x));
}
};

/* convenience functions for the compose_gx_op_hx adapter
*/
template <class OP1, class OP2, class OP3>
inline compose_gx_op_hx_t<OP1,OP2,OP3>
compose_gx_op_hx (const OP1& o1, const OP2& o2, const OP3& o3) {
return compose_gx_op_hx_t<OP1,OP2,OP3>(o1,o2,o3);
}

class Test1
: public std::unary_function<int,bool>
{
public:
bool operator()(int) const { std::cout << "Test1" << std::endl;
return true; }
};

class Test2
: public std::unary_function<int,bool>
{
public:
bool operator()(int) const { std::cout << "Test2" << std::endl;
return false; }
};

int main()
{
std::vector<int> vInt(1,1);

std::find_if(vInt.begin(), vInt.end(),
compose_gx_op_hx(std::logical_or<bool>(), Test1(), Test2()));

return 0;
}

The problem is that not a *general* solution because the
logical_operator is hardcoded (|| in this case) even if it is the
first template parameter.

If I use the commented statement
return op1(op2(x),op3(x));
instead of
return op2(x) || op3(x);
both Test1() and Test2() are always called and there is no short
evaluation.

Many thanks for any help.

Marco.
Jul 22 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
marco_segurini wrote:
when the following code is executed

bool Test1();
bool Test2();

...
if (Test1() || Test2()) { ... }
...

Test2 is executed only if Test1 returns false.

I am trying to create a predicate for find_if with the same behaviour:

find_if(iterBegin,iterEnd, Test1 || Test2)
For do this I have modificated the boost::compose_f_gx_hx template in
this way:

#include <algorithm>
#include <functional>
#include <iostream>
#include <vector>

/* class for the compose_gx_op_hx adapter
*/
template <class OP1, class OP2, class OP3>
class compose_gx_op_hx_t
: public std::unary_function<typename OP2::argument_type,
typename OP1::result_type>
{
private:
OP1 op1; // process: op2(x) op1 op3(x)
OP2 op2;
OP3 op3;
public:
// constructor
compose_gx_op_hx_t (const OP1& o1, const OP2& o2, const OP3& o3)
: op1(o1), op2(o2), op3(o3) {
}

// function call
typename OP1::result_type
operator()(const typename OP2::argument_type& x) const {
return op2(x) || op3(x);
// return op1(op2(x),op3(x));
}
};

/* convenience functions for the compose_gx_op_hx adapter
*/
template <class OP1, class OP2, class OP3>
inline compose_gx_op_hx_t<OP1,OP2,OP3>
compose_gx_op_hx (const OP1& o1, const OP2& o2, const OP3& o3) {
return compose_gx_op_hx_t<OP1,OP2,OP3>(o1,o2,o3);
}

class Test1
: public std::unary_function<int,bool>
{
public:
bool operator()(int) const { std::cout << "Test1" << std::endl;
return true; }
};

class Test2
: public std::unary_function<int,bool>
{
public:
bool operator()(int) const { std::cout << "Test2" << std::endl;
return false; }
};

int main()
{
std::vector<int> vInt(1,1);

std::find_if(vInt.begin(), vInt.end(),
compose_gx_op_hx(std::logical_or<bool>(), Test1(), Test2()));

return 0;
}

The problem is that not a *general* solution because the
logical_operator is hardcoded (|| in this case) even if it is the
first template parameter.

If I use the commented statement
return op1(op2(x),op3(x));
instead of
return op2(x) || op3(x);
both Test1() and Test2() are always called and there is no short
evaluation.


It's a known problem. For example, if you overload operator || or
operator &&, you cannot make them behave like the built-in ones do
(WRT short-cutting or specific order of evaluation or existence of
a sequence point). It's a limitation of the language.

In order to achieve what you want you'd have to basically repeat
what the language defines about the logical operators. You can do
it using specialisations. Instead of making a generic template,
you should probably make two templates, one for OR and one for AND.
The 'OR' will do as you wrote

return op2(x) || op3(x);

and the 'AND' will do

return op2(x) && op3(x);

Otherwise, your solution is declaring "operator traits" with the order
of operand evaluation either predefined or undefined, and then, again,
implement variations of the execution based on the traits:

if (op1::traits::do_second_if_first_false) {
bool x = op2(x);
if (!x)
return op3(x);
else
return x;
}
else if (op1::traits::do_second_if_first_true) {
bool x = op2(x);
if (x)
return op3(x);
else
return false;
}
else
return op1(op2(x), op3(x));

Then you could (optionally) define those traits (or, specialise them)
for 'or' and 'and' and use generic ones for anything else.

Victor
Jul 22 '05 #2

P: n/a
> if (Test1() || Test2()) { ... }
...

Test2 is executed only if Test1 returns false.

I am trying to create a predicate for find_if with the same behaviour:

find_if(iterBegin,iterEnd, Test1 || Test2)


If you are not hooked to the find_if there is another way of implementing
such a behaviour
I once used something like:
---------------
for(LIST::iterator i=l.begin();i!=l.end();i++)
if(pred1(*i) || pred2(*i))
{
//do stuff
}
---------------
//jota
Jul 22 '05 #3

P: n/a
marco_segurini wrote:
[snip]
instead of
return op2(x) || op3(x);
both Test1() and Test2() are always called and there is no short
evaluation.


ALl of that seems a lot of work for a simple:

bool Test()
{
return Test1() || Test2();
}

find_if( iterBegin, iterEnd, Test )
--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.