让我们考虑一下:
switch(x)
{
case something:
{
for(something_else : some_container)
{
if(a_condition)
{
// BREAK OUT OF THE SWITCH
}
}
some_statements();
break;
}
}
我怎样才能以最优雅的方式从switch
语句中的循环中逃脱,因为我不想运行some_statements();
.
当然,一个位置良好的goto
可以很好地解决这个问题,但解决方案可以被认为是优雅的:
switch(x)
{
case something:
{
for(something_else : some_container)
{
if(a_condition)
{
goto escape_route;
}
}
some_statements();
break;
}
}
escape_route:
// Hurrah, freedom
还有一个标志可以解决这个问题:
switch(x)
{
case something:
{
bool flag = true;
for(something_else : some_container)
{
if(a_condition)
{
flag = false;
break;
}
}
if(flag)
{
some_statements();
}
break;
}
}
但是,让我们说,为了挑战,我正在寻找这个问题的其他解决方案(请注意:切换后还有更多语句,return
ing 不是一种选择)。
有什么想法吗?
一般来说,这是少数几种情况之一,通常认为使用 gotos 是可以的。但是,由于 c++11,我更喜欢使用立即调用的 lambda和 return 语句:
[&]{
switch(x)
{
case something:
{
for(something_else : some_container)
{
if(a_condition)
{
return ;
}
}
some_statements();
break;
}
}
}(); //<- directly invokes the lambda
一旦你有了这个,想想你是否想把整个块放到一个单独的命名函数中。
goto 版本还可以,但更好的选择可能是使用函数并在特殊情况下从中返回:
status_t func (void)
{
status_t status = default_value;
switch(x)
{
case something:
{
for(something_else : some_container)
{
if(a_condition)
{
return status;
}
}
some_statements();
break;
}
}
return status;
}
这里的优点是它允许您使用状态变量(用于错误代码等)。
另一种选择是异常处理。
goto
看起来没问题。不要想太多——你只会让它更加纠结。
不过,这是针对一般情况的。您的特定用途看起来可以折叠成对<algorithm>
的漂亮调用。
switch(x)
{
case something:
{
if(std::any_of(
begin(some_container),
end(some_container),
[](auto &&e) { return a_condition(e); }
))
break;
some_statements();
break;
}
}
请注意,这将调用一个执行早期返回的函数,如果它返回true
,则会立即break
s。
是的,您可以使用自己的函数/lambda 来模仿此模式来代替std::any_of
。
不,如果您的函数本身不像std::any_of
那样有意义,这不是一个好主意。
我可能会将函数拆分为子函数,从而消除您在循环内中断的需要,如下所示:
void foo(/*...*/)
{
for (auto something_else : some_container) {
if (a_condition) {
return;
}
}
some_statements();
}
然后
switch (x)
{
case something: { foo (/*...*/); break; }
case something2: { foo2(/*...*/); break; }
case something3: { foo3(/*...*/); break; }
// ...
}