如何从开关C++内部的回路中断开



让我们考虑一下:

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;
}
}

但是,让我们说,为了挑战,我正在寻找这个问题的其他解决方案(请注意:切换后还有更多语句,returning 不是一种选择)。

有什么想法吗?

一般来说,这是少数几种情况之一,通常认为使用 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,则会立即breaks。
是的,您可以使用自己的函数/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; }
// ...
}

最新更新