Reputation: 321
While refactoring code to minimize the number of lines of code, I wonder if it's possible to combine two similar if-statements with the only difference being the comparison operator, e.g.
if (a > b) a=b;
if (a < b) a=b;
using the ternary operator (?) to select the comparison operator, e.g.
if (a (c?<:>) b) a=b;
My compiler doesn't throw any errors or warnings but I wonder if it really works intentionally.
Upvotes: 2
Views: 1244
Reputation: 218268
From your example, I would simply do
a = (c ? std::max(a, b) : std::min(a, b));
Upvotes: 1
Reputation: 26362
Just for fun, I can suggest the following syntax:
if (a, cmp(c, std::less{}, std::greater{}), b) ...
as an approximation to
if (a (c ? < : >) b) ...
Implementation:
template<class True, class False>
class cmp {
public:
cmp(bool flag, True if_true, False if_false)
: flag_(flag), if_true_(if_true), if_false_(if_false) {}
private:
template<class Lhs>
class Proxy {
public:
Proxy(const Lhs& lhs, cmp comparator)
: lhs_(lhs), comparator_(comparator) {}
template<class Rhs>
bool operator,(const Rhs& rhs) {
if (comparator_.flag_)
return comparator_.if_true_(lhs_, rhs);
else
return comparator_.if_false_(lhs_, rhs);
}
private:
const Lhs& lhs_;
const cmp comparator_;
};
template<class Lhs>
friend auto operator,(const Lhs& lhs, cmp comparator) {
return Proxy<Lhs>(lhs, comparator);
}
const bool flag_;
const True if_true_;
const False if_false_;
};
Upvotes: 0
Reputation: 123431
I would not use a ternary operator here, but rather a plain old boring condition for if
:
if ( (c && a < b) || (!c && a > b) ) a = b;
I admit, wether this is more readable than something else is up to the reader to decide.
Upvotes: 1
Reputation: 5095
Arithmetics to the rescue!!!
if((a-b)*(((int) c)*2 - 1) < 0)
a=b;
I hope the <
is the right way round.
Upvotes: 0
Reputation: 234875
A C++17 way:
if (auto s = 2 * !!c - 1; s * a > s * b) a = b;
s
is the sign of c
, and multiplying a
and b
by s
when it's -1
effectively reverses >
. One hazard though is the attempted negation of a 2's complement signed type currently at the minimum.
Upvotes: 3
Reputation: 26362
Solution with lambdas:
const auto lt = [](int a, int b) { return a < b; };
const auto gt = [](int a, int b) { return a > b; };
if ((c ? +lt : +gt)(a, b))
a = b;
+
converts lambda into a function pointer, so +less
and +greater
have the same type.
Upvotes: 3
Reputation: 63152
No. <
and >
are operators, not expressions. Operator ?:
takes 3 expressions.
The conditional operator expressions have the form
E1 ? E2 : E3
The first operand of the conditional operator is evaluated and contextually converted to bool. After both the value evaluation and all side effects of the first operand are completed, if the result was true, the second operand is evaluated. If the result was false, the third operand is evaluated.
Upvotes: 2
Reputation: 36513
You can use std::less
and std::greater
:
int a = 0, b = 0;
if(c ? std::less<int>{}(a, b) : std::greater<int>{}(a, b))
a = b;
Do note that this is considered bad practice because it's quite unreadable and thus shouldn't be used in production code unless there's a particular reason.
Upvotes: 4