У меня есть шаблон, который я основал здесь на ответе, и он работает на clang, gcc и MSVC. Я публикую это здесь в надежде, что это будет полезно для других, и потому что ответы здесь помогли мне сформулировать это.
#ifdef WIN32
# define ONCE __pragma( warning(push) ) \
__pragma( warning(disable:4127) ) \
while( 0 ) \
__pragma( warning(pop) )
#else
# define ONCE while( 0 )
#endif
И я использую это так:
do {
// Some stuff
} ONCE;
Вы также можете использовать это в макросах:
void SomeLogImpl( const char* filename, int line, ... );
#ifdef NDEBUG
# define LOG( ... )
#else
# define LOG( ... ) do { \
SomeLogImpl( __FILE__, __LINE__, __VA_ARGS__ ); \
} ONCE
#endif
Это также работает для случая, указанного выше, если F использует 'ONCE' в функции:
#define F( x ) do { f(x); } ONCE
...
if (a==b) F(bar); else someFunc();
Редактировать: Несколько лет спустя я понял, что забыл добавить шаблон, для которого я на самом деле написал этот макрос - шаблон "switch-like-a-goto":
do {
begin_some_operation();
if( something_is_wrong ) {
break;
}
continue_big_operation();
if( another_failure_cond ) {
break;
}
finish_big_operation();
return SUCCESS;
} ONCE;
cleanup_the_mess();
return FAILURE;
Это дает вам структуру try / finally-ish, которая является более структурированной, чем грубое переход к вашему коду очистки и возврата. Использование этого макроса ONCE вместо while (0) выключает VS.