2

The following #define partially works:

#define OUT(x) \
   if(x > 0) cout << "Hello "; \
   if(x > 1) cout << x+1

OUT(1) << "message";     // OK

if(0) {
   OUT(1) << "message";     // OK, nothing printed
}

if(0)
   OUT(1) << "message";     // NO, printed anyway

I understand why it does not work (if(0) applies to if(x > 0) only).
I cannot find a way to make it work. Consider that I cannot put braces in the define, otherwise I will not be allowed to use the insertion operator.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Pietro
  • 12,086
  • 26
  • 100
  • 193

2 Answers2

5

Updated to print "Hello"

It can be done this way (oh the ugliness!):

#define OUT(x) if((x > 0 ? cout << "Hello " : cout), x > 1) cout << x+1

This is a "standard" comma operator trick that allows additional expressions to be evaluated within the if conditional without affecting the branch taken in the end.

In this case one expression is added: a ternary operator that evaluates the original condition x > 0. An expression (not a statement, but this restriction does not matter here) that produces the desired side effect is placed in the "true" branch of the ternary. It does not matter at all what the "false" branch evaluates to, so long as it's the same type as (or can be implicitly converted to) the result of the "true" branch.

Here the "true" branch returns an ostream&, so the easiest way is to return cout from the "false" branch as well and call it a day.

Answer to the original question

In the originally posted case (with x and y) the macro would be

#define OUT(x) if((x > 0 ? y = x : 0), x > 1) cout << x+1

which for this specific case could be also written as

#define OUT(x) if((y = x > 0 ? x : y), x > 1) cout << x+1

See it in action.

Jon
  • 428,835
  • 81
  • 738
  • 806
2

Create a function which returns a reference to the std::cout and then use this function in your MACRO.

#define OUT(x) MyOut( x, y )

where MyOut is:

std::ostream& MyOut( int x, int& yRef )
{
    if(x > 0) yRef = x;
    if(x > 1) 
    {
        std::cout << x+1;
        return std::cout;
    }
    return SomeNoOpOstream;
}
Nick
  • 25,026
  • 7
  • 51
  • 83
  • No they'd just have to be in scope where the code is called. Notice that the macro doesn't write to `cout` if `x <= 1`. You'd need to return some form of "noop" ostream from your function. (Probably doable I guess.) – Mat May 16 '12 at 10:31
  • 1
    There's a `y` in the function which will not be in scope. – Jon May 16 '12 at 10:31
  • @Jon if the MACRO has access to `y` then why not a function? – Nick May 16 '12 at 10:33
  • 1
    You'll need a bit more: myout needs to take `y` as an `int&` (non-const) and OUT needs to pass it in. `y` is visible from the macro if it's a local variable. It's not in scope in the function unless its a global. – Mat May 16 '12 at 10:34
  • I've assumed from the little code provided that y is a global. If not then you're correct and y would need passing in. – Nick May 16 '12 at 10:35