// Feature: Labeled Loop Variable // // Note: The code below is pseudo code and therefore cannot be compiled with // current compilers. // This isn't a proposal, these are just ideas (thoughts) :). template <typename T> void Test(const std::vector<T>& data) { // // Syntax (Lines marked with + are additions/modifications): // ----------------------------------------------------------------------- // // + decl-specifier-mod: // + constexpr // + static // + thread_local // + cv-qualifier-seq opt // // + labeled-for: // + decl-specifier-mod opt identifier : // // + labeled-for-default-expression: // + -> init-declarator // // iteration-statement: // + for labeled-for opt ( init-statement condition opt ; expression opt ) labeled-for-default-expression opt // + for labeled-for opt ( for-range-declaration : for-range-initializer ) labeled-for-default-expression opt // // + labeled-break-expression: // + : expr-or-braced-init-list opt // // + labeled-break-statement-expression: // + identifier labeled-break-expression opt // + expr-or-braced-init-list // // jump-statement: // + break labeled-break-statement-expression opt ; // continue ; // return expr-or-braced-init-list opt ; // goto identifier ; // ----------------------------------------------------------------------- // Examples // ----------------------------------------------------------------------- // // The below loop will emit a variable definition (labeled loop variable) // outside of the for-loop with an optional default initialization. // // The labeled loop variable cannot be accessed inside the for-loop and // can only be indirectly modified by using the 'break' keyword with an // expression as operand. // This has the advantage that we can use the name of the // labeled loop variable as label to break out of that loop. // // There are several ways one can use the 'break' keyword in this context. // // 1.) // // This is emitted before the loop: // sugar for -> int calc_loop = 0; for calc_loop: (auto& item : data) -> int{0} { if (item()) { continue; } break 1; } if (calc_loop == 0) { // The loop did not break } else { // calc_loop = 1 } // 2.) // // The labeled loop variable 'exit_code' which type is std::optional<int> // is default initialized. // // This is emitted before the loop: // sugar for -> std::optional<int> exit_code; for exit_code: (auto& item : data) -> std::optional<int>{} { if (item()) { continue; } break 1; } if (exit_code) { auto val = *exit_code; // Deal with the error "returned" by the loop } // 3.) // // It's possible to break out of an outer labeled for-loop // by using its label. // One can also specify an additional expression to be assigned // to the labeled loop variable associated with the label. for loop: (auto& item : data) -> std::optional<int>{} { for (auto nested : item) { if (nested.cond1) { // This is going to break out of the outer loop. // Note that this isn't assigning an expression, this works // because you can't access the labeled loop variable inside the // loop. It can only be used as a label. break loop; } if (nested.special_cond) { break loop: nested.val; } if (nested.super) { break loop: 13 + nested.val; } } } if (loop) { auto error = *loop; // Process the error... } // More thoughts: // // This whole for-loop-statement can be considered as an expression which // returns the labeled loop variable, therefore the explicit loop variable // can be omitted. // // The syntax can be simplified to something like this: auto loop = for (auto& item : data) -> std::optional<int>{} { for nested_loop: (auto nested : item) { if (nested.cond1) { break loop; } if (nested.special_cond) { break loop: nested.val; } if (nested.super) { break loop: 13 + nested.val; } if (nested.naeh) { break nested_loop; } } }; if (loop) { // Do the processing... } }
Why these thoughts? Well, I've been thinking of getting myself to know clang better. So the idea is to implement some playful new C++ syntax in clang :P
If this idea seems like a "okay"-idea, I might think of implementing this in clang.
The much simpler for loop exit strategies proposal covers the more reasonable cases of this. As for breaking to particular loops and such, no. That's way too much complexity. If your loops are that complicated, maybe you should be using a different construct.