I consider this to be a valid use of goto
, but I myself use flags for this.
As an experiment, I've also ported Java's named loops to C++, using macros.
Usage:
for (int i = 0; i < 10; i++) LOOP_NAME(foo)
{
for (int j = 0; j < 10; j++)
{
if (i == 5 && j == 5)
break(foo);
}
}
Implementation:
#define LOOP_NAME(name) \
/* The variable in the conditions prevents `BREAK/CONTINUE` from */\
/* being used outside of the loop with the matching name. */\
if ([[maybe_unused]] constexpr bool _namedloop_InvalidBreakOrContinue = false) \
{ \
[[maybe_unused]] LOOP_NAME_impl_cat(_namedloop_break_,name): break; \
[[maybe_unused]] LOOP_NAME_impl_cat(_namedloop_continue_,name): continue; \
} \
else
#define LOOP_NAME_impl_cat(x, y) LOOP_NAME_impl_cat_(x, y)
#define LOOP_NAME_impl_cat_(x, y) x##y
#define BREAK(name) goto LOOP_NAME_impl_cat(_namedloop_break_,name)
#define CONTINUE(name) goto LOOP_NAME_impl_cat(_namedloop_continue_,name)
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif
#define break(x) BREAK(x)
#define continue(x) CONTINUE(x)
#ifdef __clang__
#pragma clang diagnostic pop
#endif