Question

Is it possible to have a blank 2nd or 3rd argument for the ternary operator or have one that is non-context-specific and means "do nothing"? In the following example, I want a ternary operator to multiply an integer variable by two if it is even or do nothing otherwise. I cannot think of anything for the third argument other than self-assignment, adding or subtracting zero, or multiplication or division by one. Anyway, they are all context-specific. I want something that means "do nothing" for all ternary operators. I tried leaving the argument blank, but it wouldn't compile.

#include <iostream>

int main()
{
    int x = 5;
    (x % 2 == 0) ? x *= 2 : x = x; // or x += 0, x -= 0, x *= 1, or x /= 1
    std::cout << x << std::endl;
    return 0;
}

Is there any solution that does not involve a restatement of variables, functions, or objects that are already there? For instance, consider two functions foo and goo, where the foo returns a bool. Assume neither function can be called again for some reason, such as change of state on subsequent calls.

int main()
{
    ( foo() ) ? goo() : ; // won't compile
    return 0;
}
Was it helpful?

Solution

If you're going to use a ternary operator, you probably want to assign its result:

x = (x % 2 == 0) ? 2 * x : x;

Personally, I think I'd just use a tiny bit of math:

x <<= ((x & 1) ^ 1);

x&1 gives the least significant bit of x, which will be 1 if x is odd, and 0 if it's even. The ^ 1 part flips that bit, so it gives 1 if x was even and 0 if x was odd. We then shift x left by that many bits. Shifting by 0 bits obviously leaves x unchanged. Shift left one bit multiplies x by 2.

As for why the latter would (or at least might) be preferable, it mostly comes down to a question of whether you really care about performance in this situation. If you're in situation where performance doesn't matter, then something like if ((x%2)==0) x *= 2; is probably your best choice.

I'd at least guessed that at least part of the reason for the question was a concern for efficiency though. If so, the purely mathematical method is likely to be a better choice. For example, let's consider the code VC++ produces for the two:

; mathematical version:
mov eax, DWORD PTR _x$[esp-4]
mov ecx, eax
not ecx
and ecx, 1
shl eax, cl

[note: for this source code, g++ produces nearly identical object code].

Ignoring the (possible) time to load x from memory, this should execute in no more than 4 clock cycles on just about any Intel processor going back to around the 386. Better still, I'd expect just about any compiler for any processor to produce pretty similar results -- a straightforward, literal translation from the source code to assembly language for nearly any reasonable processor is going to do the actual math in four instructions, each of which is about as simple and fast as possible.

The version using the if statement comes out like this:

; Line 2
    mov ecx, DWORD PTR _x$[esp-4]
    mov eax, ecx
    and eax, -2147483647            ; 80000001H
    jns SHORT $LN5@f
    dec eax
    or  eax, -2                 ; fffffffeH
    inc eax
$LN5@f:
    lea eax, DWORD PTR [ecx+ecx]
    je  SHORT $LN1@f
; Line 3
    mov eax, ecx
$LN1@f:

As compiling goes, this isn't too bad. It's at least avoiding the div that would be the obvious way of implementing a %2. Unfortunately, it's still not really smart enough to be competitive -- it still has a couple of branches, one of which probably won't be very predictable, so around half the time we'll pay the price of a mispredicted branch.

Depending on the compiler, you can (and will) see better than this. For example using g++ instead, I get this:

    mov eax, DWORD PTR [ebp+8]
    and eax, 1
    test    eax, eax
    jne L2
    sal DWORD PTR [ebp+8]
L2:
    mov eax, DWORD PTR [ebp+8]

While certainly better than VC++ did for this code, that's still nowhere near as good as the mathematical version. In particular, unless that least significant bit is fairly predictably even or odd, that branch is likely to be mi-predicted about half the time.

Bottom line: at very best, this might come close to matching the mathematical version -- but that'll depend both on the compiler and the input data cooperating. With anything but the most fortuitous combination of compiler and input data, it'll almost certainly be slower by at least 2x, and 10x wouldn't be even mildly surprising.

Of course, depending on what flags, compiler version, etc., I use, I might be able to get better results out of either compiler than I actually did. With some persistence, I might even get results equal to the mathematical version of the code. Unless I knew the target compiler and CPU pretty well, I'd be pretty uncertain about even getting as good of results though -- and chances of them being better strike me as extremely slim at best.

OTHER TIPS

(x % 2 == 0) ? x *= 2 : x = x;

The conditional operator is not an if statement, it is meant to produce a value, if you don't need the value, as is the case above, just type the if as it is meant to be:

if (x%2==0) x*=2;

Which is simpler to read and maintain and equivalent in all other things. If you think your code will be better in any way, reconsider it.

From a comment in the question it seems that you want to learn how it works, not just writing weird looking code. If that is the case, the operator is very interesting, but the the interesting bits are not whether you can use it with 3 or 2 operators. Rather the most interesting behavior of the operator is what it yields (again, it is designed to yield a value) when the second and third arguments are not of the same type.

As all other value producing expressions, the type of the ternary operator is fixed regardless of what the value of the condition is, so the compiler must determine what the type of the whole expression is and it must be a type that is compatible with both arguments. The rules are rather interesting and too complex to explain here, but you should take a look at Conditional Love: FOREACH Redux.

Also, while it does not fit your question, and this is the reasons why I did not bring it before, not both branches need to yield a value, one or both of them can be a throw expression, in which case the type is that of the other argument. Additionally, if both are throw expressions or expressions of type void the type of the ternary operator is void itself.

There is no way you can skip parameters of ternary operator. If the functions required to be called once then you can use like this. If both the return value of foo() and goo() is boolean you can use the simple or operator to get the final result.

bool ResultOfFoo =  foo();
bool ResultOfGoo = goo();

bool RequiredResult = ResultOfFoo ? ResultOfGoo : ResultOfFoo ;

Optimization

bool RequiredResult = ResultOfFoo || ResultOfGoo;

Currently, (x % 2 == 0)? x *= 2 : x = x is no better than an if statement:

if (x % 2 == 0) x *= 2; // This is okay for one-liners.

You don't need to write x = x if you want to keep the ternary operator, you can make the whole line an assignment statement and use the ternary operator to choose the value:

x = (x % 2 == 0)? x * 2 : x;

I'd just stick with the if statement though. It seems clearer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top