Проверка списков и запуск обработчиков - PullRequest
1 голос
/ 28 октября 2008

Я пишу код, который выглядит так:

set<int> affected_items;
while (string code = GetKeyCodeFromSomewhere())
{
    if (code == "some constant" || code == "some other constant") {
        affected_items.insert(some_constant_id);
    } else if (code == "yet another constant" || code == "the constant I didn't mention yet") {
        affected_items.insert(some_other_constant_id);
    } // else if etc...
}
for (set<int>::iterator it = affected_items.begin(); it != affected_items.end(); it++)
{
    switch(*it)
    {
        case some_constant_id:
           RunSomeFunction(with, these, params);
        break;
        case some_other_constant_id:
           RunSomeOtherFunction(with, these, other, params);
        break;
        // etc...
    }
}

Причина, по которой я заканчиваю писать этот код, заключается в том, что мне нужно запускать функции во втором цикле только один раз, даже если я получил несколько кодов клавиш, которые могут привести к их запуску.

Это просто не лучший способ сделать это. Есть ли более аккуратный способ?

Ответы [ 4 ]

2 голосов
/ 28 октября 2008

Один из подходов - поддерживать карту от строк до логических значений. Основная логика может начинаться с чего-то вроде:

if(done[code])
    continue;
done[code] = true;

Затем вы можете выполнить соответствующее действие, как только определите код.

Другой подход заключается в сохранении чего-либо исполняемого (объект, указатель на функцию и т. Д.) В своего рода «список дел». Например:

while (string code = GetKeyCodeFromSomewhere())
{
    todo[code] = codefor[code];
}

Инициализировать codefor, чтобы он содержал соответствующий указатель на функцию или подклассы объекта из общего базового класса для каждого значения кода. Если один и тот же код появляется более одного раза, соответствующая запись в todo просто перезаписывается с тем же значением, которое уже имело. В конце переберите todo и запустите все его члены.

1 голос
/ 28 октября 2008

Это, конечно, не аккуратно, но вы могли бы поддерживать набор флагов, которые говорят, вызывали ли вы эту конкретную функцию или нет. Таким образом, вам не нужно сохранять вещи в наборе, у вас просто есть флаги.

Поскольку существует (предположительно из того, как написано) фиксированное во время компиляции число различных блоков if / else, вы можете сделать это довольно легко с помощью набора битов.

1 голос
/ 28 октября 2008

Поскольку вам кажется, что вам не нужны фактические значения в наборе, вы можете заменить его установочными битами в int. Вы также можете заменить логику поиска по линейному времени на логику поиска по времени. Вот окончательный код:

// Ahead of time you build a static map from your strings to bit values.
std::map< std::string, int > codesToValues;
codesToValues[ "some constant" ] = 1;
codesToValues[ "some other constant" ] = 1;
codesToValues[ "yet another constant" ] = 2;
codesToValues[ "the constant I didn't mention yet" ] = 2;

// When you want to do your work
int affected_items = 0;
while (string code = GetKeyCodeFromSomewhere())
    affected_items |= codesToValues[ code ];

if( affected_items & 1 )
    RunSomeFunction(with, these, params);
if( affected_items & 2 )
    RunSomeOtherFunction(with, these, other, params);
// etc...
0 голосов
/ 28 октября 2008

Очевидно, что это будет зависеть от конкретных обстоятельств, но может быть лучше, чтобы вызываемые вами функции отслеживали, были ли они уже запущены, и выходили раньше, если это необходимо.

...