epp
epp

Reputation: 321

Is it possible in C++ to use ternary operator to select a comparison operator inside an if-statement?

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

Answers (8)

Jarod42
Jarod42

Reputation: 218268

From your example, I would simply do

a = (c ? std::max(a, b) : std::min(a, b));

Upvotes: 1

Evg
Evg

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

463035818_is_not_an_ai
463035818_is_not_an_ai

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

n314159
n314159

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

Bathsheba
Bathsheba

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

Evg
Evg

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

Caleth
Caleth

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

Hatted Rooster
Hatted Rooster

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

Related Questions