Связанные списки шаблонных классов против функции ПТР


Сейчас я занимаюсь разработкой библиотеки для иерархической задачи. На каждом этапе иерархии есть несколько "инструментов" под рукой. Если в состоянии одним инструментом успешного решения передается на следующий (N+1) состоянии. Если все инструменты стадия П выполнена, мы возвращаемся в состояние Н-1 (предыдущих) и пусть на предыдущем этапе справиться с проблемой.

У меня есть две идеи, как структурировать эту проблему. Один использует связанный список шаблонных классов, другой привязывает непосредственно к функции запуска следующего этапа. Мой вопрос, является любой из них превосходит другой (или оба ущербные) и почему?

Первое решение использует шаблоны, чтобы создать связанный список шаблонных классов.

template <typename Input, typename Output>
struct BaseSolver
{
    virtual boost::optional<Output> run(const Input& _input) = 0;
};

template<typename Input>
struct BaseStage
{
    virtual bool runAndRecover(const Input &_input)
    {
        return true;
    }
};

template<typename Input, typename Output>
struct Stage1 : BaseStage<Input>
{
    bool run(const Input& _input)
    {
        for(const auto& solver : solvers_)
        {
            const auto currentResult = solver->run(_input);
            if(currentResult && nextStage->runAndRecover(currentResult.get()))
            {
                return true;
            }
        }
        return false;
    }

    std::vector<boost::shared_ptr<BaseSolver<Input, Output>>> solvers_;

    BaseStage<Output>* nextStage;
};

Это другое решение. Он был привязан только к запуска (функции) следующий этап

template<typename Input, typename Output>
struct Stage2
{
    typedef boost::function<boost::optional<Output> (Input)> SolverFunction;
    typedef boost::function<bool(Output)> NextStage;

    bool run(const Input& _input)
    {
        for(const auto& solver : solverFunctions_)
        {
            const auto solverResult = solver(_input);
            if(solverResult && nextStage_(solverResult.get()))
            {
                return true;
            }
        }
        return false;
    }

    std::vector<SolverFunction> solverFunctions_;
    // will be bind to the next stage::run
    NextStage nextStage_;
};

ЗЫ: обе версии скомпилировать и запустить в качестве прототипа.



Комментарии
2 ответа

Второе-проще, аккуратнее и избегает virtual функции. Предпочитаю std::function за boost::function если последний дает вам что-то дополнительное, что не здесь

2
ответ дан 14 февраля 2018 в 03:02 Источник Поделиться

Ваш выбор здесь между следующими:


  • функтор объект, который может удерживать состояние между вызовами, или

  • указатель на функцию, которая не должна занимать государство.

Я предполагаю, что вы не используете static переменные в функции, так как они не локального потока и может быть сброшена между вызовами.

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

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

0
ответ дан 15 февраля 2018 в 09:02 Источник Поделиться