Блок кода в макросе препроцессора C++ не работает без фигурных скобок


Частично работает следующее #define:

#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
Я понимаю, почему это не работает (if(0) относится только к if(x > 0)).
Я не могу найти способ заставить его работать. Учтите, что я не могу поставить фигурные скобки в define, иначе мне не разрешат использовать оператор вставки.
2 2

2 ответа:

Обновлено для печати "Hello"

Это можно сделать так (о уродство!):

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

Это "стандартный" трюк оператора запятой, который позволяет вычислять дополнительные выражения в пределах условного if, не затрагивая ветвь, взятую в конце.

В этом случае добавляется одно выражение: тернарный оператор, который вычисляет исходное условие x > 0. Выражение (не утверждение, но это ограничение здесь не имеет значения), которое производит желаемую сторону эффект помещается в "истинную" ветвь Троицы. Не имеет никакого значения, к чему приводит" ложная " ветвь, если она имеет тот же тип, что и результат "истинной" ветви (или может быть неявно преобразована в него).

Здесь "истинная" ветвь возвращает ostream&, поэтому самый простой способ-вернуться cout из "ложной" ветви и назвать ее днем.

Ответ на первоначальный вопрос

В первоначально опубликованном случае (с x и y) макрос будет быть

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

, который для данного конкретного случая может быть также записан как

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

Увидеть его в действии.

Создайте функцию, которая возвращает ссылку на std::cout, а затем используйте эту функцию в своем макросе.

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

Где MyOut:

std::ostream& MyOut( int x, int& yRef )
{
    if(x > 0) yRef = x;
    if(x > 1) 
    {
        std::cout << x+1;
        return std::cout;
    }
    return SomeNoOpOstream;
}