Как изменить этот цикл while, чтобы избавиться от «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; }Я бы лучше нашел более чистый способ выразить эту логику.

Этот упрощенный пример может показаться хорошей идеей сделать сопоставление с образцом более общим, а не иметь MatchesPatternA, MatchesPatternB, MatchesPatternCи др. функции. Но в моей ситуации закономерности довольно сложны, и я пока не готов их обобщать. Поэтому я хочу сохранить эту часть как есть, отдельные функции.

Какие-нибудь изящные идеи? Спасибо!

0

Решение

Если у вас есть доступ к C ++ 11, я хотел бы предложить другое решение. По сути, я создал контейнер обработчиков и действий, которые можно настроить во время выполнения. Это может быть за или против вашего дизайна в зависимости от ваших требований. Вот:

#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();
}
}
2

Другие решения

Я бы порекомендовал использовать функцию, которая выполняет сопоставление с образцом (но не влияет на результат), а затем набор функций, которые действуют на различные параметры:

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

Таким образом, вы четко отделяете соответствие от обработки, цикл просто диспетчер

3

Рассмотрим интерфейс:

class IMatchPattern
{
public:
virtual bool MatchesPattern(const Element& e) = 0;
};

Затем вы можете организовать контейнер объектов, реализующих IMatchPattern, чтобы обеспечить итеративный доступ к каждому методу сопоставления с шаблоном.

2

Вы можете изменить свой 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;
1

Хорошо, я закончил тем, что переписал цикл более похожий на это.

Огромная благодарность и благодарность Юсуши, dasblinkenlight, Дэвиду Родригесу за их помощь; этот ответ основан на комбинации их ответов.

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
}

Теперь я знаю, что есть еще возможности для совершенствования, см. Ответы Матеуш Пуш и Майкла Ш. Тем не менее, это достаточно хорошо, чтобы ответить на мой первоначальный вопрос, и пока подойдет. Я рассмотрю вопрос об улучшении этого в будущем.

Если вам интересно увидеть реальный код (не упрощенная версия), смотрите здесь:

https://github.com/shurcooL/Conception/blob/38f731ccc199d5391f46d8fce3cf9a9092f38c65/src/App.cpp#L592

Спасибо всем еще раз!

1

Я хотел бы предложить функцию 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
}
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector