But, heads-up: there once was a version of a Unix shell written in C
with macros and support functions defined to make it look like Pascal.
Heavy emphasis on **was**.
And for example, when I once defined a WITH macro (corresponding to C#
"using"), and even enlisted help from the community with the quality
assurance of that, I thought this was the next best thing since pizza
slices. It used a similar trick internally, using an `if` to introduce a
variable for the `else` part. I have not used that macro since.
* * *
So, how to reasonably exit from a nested scope, without such shenanigans?
Let's consider the common example, a nested loop, with some nested
conditionals thrown in for good measure, plus an "at the end" action:
Code:
#include <iostream>
#include <math.h> // sqrt
using namespace std;
auto main()
-> int
{
int const max_a = 12345;
int const max_numbers = 42;
int n = 0;
int prev_c = 0;
for( int a = 1; a <= max_a; ++a )
{
for( int b = 1; b < a; ++b )
{
int const c_sq = a*a + b*b;
int const c = int( sqrt( c_sq ) + 0.5 );
if( c*c == c_sq )
{
if( c < prev_c )
{
cout << (n > 0? " " : "") << c;
++n;
if( n == max_numbers )
{
goto finished;
}
}
prev_c = c;
}
}
}
finished:
cout << endl;
cout << "Found " << n << " interesting numbers." << endl;
}
The C++ construct that is a scope that can be exited from some nested
scope, is a function, and in most all cases introducing (refactoring as)
a function is a good solution.
In C++03 that function must be a named function or a function template
instantiation. As a named function it can be at namespace scope or a
member of a local class. In C++11 it can also be an anonymous function,
as a lambda.
The code below shows a C++03-style named function refactoring:
Code:
#include <iostream>
#include <math.h> // sqrt
using namespace std;
auto list_interesting_numbers(
int const max_numbers,
int const max_a = 12345
)
-> int
{
int n = 0;
int prev_c = 0;
for( int a = 1; a <= max_a; ++a )
{
for( int b = 1; b < a; ++b )
{
int const c_sq = a*a + b*b;
int const c = int( sqrt( c_sq ) + 0.5 );
if( c*c == c_sq )
{
if( c < prev_c )
{
cout << (n > 0? " " : "") << c;
++n;
if( n == max_numbers )
{
return n;
}
}
prev_c = c;
}
}
}
return n;
}
auto main()
-> int
{
int const n = list_interesting_numbers( 42 );
cout << endl;
cout << "Found " << n << " interesting numbers." << endl;
}
Since the `goto` has been eliminated, the effect of any statement here
is clear just from inspecting the statement itself.
Also, the function is more reusable.
For some special cases of nested loops there are some other clean
alternatives. For example, looping over a rectangular set of positions
can be done with a single logical position variable. But I do not think
that the Pascal solution, of introducing extra boolean "are we finished
yet" variables, checked at every loop iteration, is clean for C++. That
solution was nice for Pascal, and also for C, where a single exit point
(SESE) is important. However, in C++ a single exit point can almost
never be relied on (so that code that does, is misguided), and one has
tools to deal with multiple exit points, namely destructors and `catch`.
Cheers & hth.,
- Alf