Делать while (false) pattern
Возможный дубликат:
Почему иногда существуют бессмысленные операторы do/while и if/else в макросах C/С++?
Почему в макросах требуется do while(false)
?
#define LOG(message, ...) \
do { \
Lock<MutualExclusion> lock (logMutex); \
.... a lot of code ...
} while (false)
Я не думаю, что он служит любой функциональной цели. Я что-то пропускаю?
Ответы
Ответ 1
Он превращает блок в один оператор. Если вы просто используете блок (т.е. Код, заключенный в {}
), могут произойти странные вещи, например
#define STUFF() \
{ do_something(); do_something_else(); }
if (cond)
STUFF();
else
//...
дополнительная полуколока разбивает синтаксис. do {} while(false)
вместо этого является одним выражением.
Подробнее об этом и других макро-трюках можно узнать здесь.
Ответ 2
Таким образом, вы вынуждены добавлять точку с запятой в конце макроса, когда используете его. Это распространенная идиома и единственный способ ее принудительного применения.
Ответ 3
Если у кого-то есть код, который делает это:
if (something)
LOG("My log message");
Это будет расширяться до:
if (something)
Lock<MutualExclusion> lock (logMutex);
// A bunch of other code
Это неверно (только первая строка будет находиться в выражении if).
Макрос гарантирует, что вызов макроса находится внутри блока кода.
Ответ 4
Люди используют его, потому что иначе вы можете испортить ваши ifs с помощью составных операторов. Представьте себе,
#define hai int x; \
x = 0;
if (condition)
hai;
else
func();
Представьте, как выглядит обработанный исходный код.
if (condition)
int x;
x = 0;
else
func();
О, подождите, теперь наш другой не работает.
Макросы, подобные этому, как правило, не нужны в С++.
Ответ 5
Причиной этой странной практики в #define является инкапсуляция различных назначений в цикл, который выполняется ровно один раз, поэтому макрос можно использовать как функцию. Например, с кодом, который вы опубликовали, можно написать:
if(...)
LOG(x, y);
else
// Something else
и он расширяется как
if(...)
do {...} while(false);
else
// Something else
Это не сработает без do... while (false), окружающего разные назначения, потому что это будет расширяться как
if(...)
Lock<MutualExclusion> lock (logMutex);
// Other code... Outside the if statement!
Также заставляя точку с запятой после того, как макрос делает ее похожей на функцию, и вы не получите ошибок, потому что вы добавили точку с запятой, как после нормальной функции.
Ответ 6
Он обеспечивает локальную область видимости внутри макроса.
Ответ 7
Мне кажется, что он используется только для правил определения области видимости, поэтому Lock<MutualExclusion>
выпадает из области видимости в конце блока.
Если это причина для этого, то он совершенно не исправляется:
// some other code...
string s = "oh hai";
{
Lock<MutualExclusion> lock(logMutex);
// MAGIC HAPPENS
}
s = "oh bai";