如何重构这个while循环以摆脱"continue"?
How to refactor this while loop to get rid of "continue"?
我有一个处理元素队列的while (!Queue.empty())
循环。有一系列从最高优先级到最低优先级的模式匹配器。当一个模式匹配时,相应的元素会从队列中删除,然后从顶部重新开始匹配(这样优先级最高的匹配者就有机会首先采取行动)。
所以现在它看起来像这样(一个简化版本):
while (!Queue.empty())
{
auto & Element = *Queue.begin();
if (MatchesPatternA(Element)) { // Highest priority, since it's first
// Act on it
// Remove Element from queue
continue;
}
if (MatchesPatternB(Element)) {
// Act on it
// Remove Element from queue
continue;
}
if (MatchesPatternC(Element)) { // Lowest priority, since it's last
// Act on it
// Remove Element from queue
continue;
}
// If we got this far, that means no pattern was matched, so
// Remove Element from queue
}
这是可行的,但我想以某种方式重构这个循环,以删除关键字continue
的使用。
为什么?因为如果我想将模式匹配外包给外部功能,它显然会崩溃。例如
void ExternalMatching(...)
{
if (MatchesPatternB(Element)) {
// Act on it
// Remove Element from queue
continue; // This won't work here
}
}
while (!Queue.empty())
{
auto & Element = *Queue.begin();
if (MatchesPatternA(Element)) {
// Act on it
// Remove Element from queue
continue;
}
ExternalMatching(...);
if (MatchesPatternC(Element)) {
// Act on it
// Remove Element from queue
continue;
}
// If we got this far, that means no pattern was matched, so
// Remove Element from queue
}
我不想写像if (ExternalMatching(...)) { ... continue; }
这样的重复if语句,我宁愿找到一种更干净的方式来表达这种逻辑。
这个简化的示例可能会使模式匹配看起来更通用,而不是具有不同的MatchesPatternA
、MatchesPatternB
、MatchesPatternC
等函数。但在我的情况下,模式相当复杂,我还没有准备好对它们进行概括。所以我想保持这个部分的原样,独立的函数。
有什么好主意吗?非常感谢。
如果您可以访问C++11,我想推荐另一种解决方案。Basicaly我创建了一个处理程序和操作的容器,可以在运行时进行调整。根据您的要求,它可能对您的设计有利或不利。这是:
#include <functional>
typedef std::pair<std::function<bool(const ElementType &)>,
std::function<void(ElementType &)> > HandlerData;
typedef std::vector<HandlerData> HandlerList;
HandlerList get_handlers()
{
HandlerList handlers;
handlers.emplace_back([](const ElementType &el){ return MatchesPatternA(el); },
[](ElementType &el){ /* Action */ });
handlers.emplace_back([](const ElementType &el){ return MatchesPatternB(el); },
[](ElementType &el){ /* Action */ });
handlers.emplace_back([](const ElementType &el){ return MatchesPatternC(el); },
[](ElementType &el){ /* Action */ });
return handlers;
}
int main()
{
auto handlers = get_handlers();
while(!Queue.empty()) {
auto &Element = *Queue.begin();
for(auto &h : handlers) {
// check if handler matches the element
if(h.first(Element)) {
// act on element
h.second(Element);
break;
}
}
// remove element
Queue.pop_front();
}
}
我建议使用一个进行模式匹配(但不对结果进行操作)的函数,然后使用一组对不同选项进行操作的函数:
enum EventType {
A, B, C //, D, ...
};
while (!queue.empty()) {
auto & event = queue.front();
EventType e = eventType(event); // Internally does MatchesPattern*
// and returns the match
switch (e) {
case A:
processA(event);
break;
case B:
processB(event);
通过这种方式,您可以清楚地将匹配与处理分开,循环只是一个简单的调度器
考虑一个接口:
class IMatchPattern
{
public:
virtual bool MatchesPattern(const Element& e) = 0;
};
然后,您可以组织一个实现IMatchPattern的对象容器,以允许对每个模式匹配方法进行迭代访问。
您可以更改ExternalMatching
以返回bool
,表示处理已经完成。这样,如果需要,呼叫者可以继续评估:
bool ExternalMatching(...)
{
if (MatchesPatternB(Element) {
// Act on it
// Remove Element from queue
return true;
}
return false;
}
现在你可以这样称呼它:
if (ExternalMatchin1(...)) continue;
if (ExternalMatchin2(...)) continue;
...
if (ExternalMatchingN(...)) continue;
好的,我最终重写了与此类似的循环。
非常感谢Yuushi、dasblinkenlight和David Rodríguez的帮助;这个答案是基于他们答案的组合。
bool ExternalMatching(...)
{
bool Match;
if ((Match = MatchesPatternX(Element))) {
// Act on it
} else if ((Match = MatchesPatternY(Element))) {
// Act on it
}
return Match;
}
while (!Queue.empty())
{
auto & Element = Queue.front();
if (MatchesPatternA(Element)) { // Highest priority, since it's first
// Act on it
} else if (MatchesPatternB(Element)) {
// Act on it
} else if (ExternalMatching(...)) {
} else if (MatchesPatternC(Element)) { // Lowest priority, since it's last
// Act on it
}
// Remove Element from queue
}
现在,我知道还有进一步的改进空间,见Mateusz Pusz和Michael Sh的回答。然而,这足以回答我最初的问题,现在就可以了。我将来会考虑改进它。
如果你想看看真实的代码(非简化版本),请参阅此处:
https://github.com/shurcooL/Conception/blob/38f731ccc199d5391f46d8fce3cf9a9092f38c65/src/App.cpp#L592
再次感谢大家!
我建议使用一个Factory函数,该函数将接受Element并创建一个适当的处理程序,并将接口指针返回到处理程序。
while (!Queue.empty())
{
auto & Element = *Queue.begin();
// get the appropriate handler object pointer e.g.
IPatternHandler *handler = Factory.GetHandler(Element);
handler->handle();
// clean up handler appropriately
}
- 如何循环打印顶点结构
- 如何在C++中从两个单独的for循环中添加两个数组
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 正在尝试了解输入验证循环
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 循环后如何继续阅读
- Ardunio UNO解决了多个重叠的定时器循环
- Eigen如何在容器循环中干净地附加矩阵
- 在某些循环内使用vector.push_back时出现分段错误
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 为什么我的for循环不能正确获取argv
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- while循环中while循环的时间复杂度是多少
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 为什么 for 循环和 while 循环之间的 continue 不同?
- 如何重构这个while循环以摆脱"continue"?
- 在基于 lambda 的 foreach 循环中模拟 'continue;', 'break;“
- 如何在C++中只循环"continue"一次?
- 为什么我们要尽量减少循环中break和continue的使用
- for循环和if条件内的Continue语句