Дублирование кода для «выбора времени выполнения» аргумента шаблона - PullRequest
0 голосов
/ 19 марта 2020

Я пытаюсь написать инструмент, который выполняет различные «действия» на основе заданной пользователем строки во время выполнения. Мой дизайн кода использует нетипизированный параметр шаблона класса enum, чтобы специализировать шаблон производного класса общего класса интерфейса / функциональности для каждого набора действий. Все возможные наборы действий известны во время компиляции. (Примечание: я использую C ++ 17)

enum class action {
    a, b, c //, ...
};

class Worker {
public:
    void run();
private:
    virtual void action_dependent();
};

template<action ... as>
class WorkerImpl : public Worker {
private:
    void action_dependent() override;
}

template<>
void Worker<action::a>::action_dependent() { ... }

template<>
void Worker<action::b, action::c>::action_dependent() { ... }

// ...

Чтобы «выбрать действие» во время выполнения, я сейчас делаю это:

int main(int argc, char** argv) {
    const int MODE_A = 1;
    // ...

    int mode = handle_options(argc, argv);
    std::unique_ptr<Worker> w;
    switch (mode) {
    case MODE_A:
        w = std::make_unique<WorkerImpl<action::a> >();
        break;
    case MODE_BC:
        w = std::make_unique<WorkerImpl<action::b, action::c> >();
        break;
    // etc. ....
    }
    w->run();
}

Этот переключатель выглядит как ненужный код -дублирование, если я добавлю много действий / специализаций. У меня была другая идея - использовать что-то вроде

const std::map<std::string, Worker> MODE_MAP = {
    {"a", WorkerImpl<action::a>()},
    {"bc", WorkerImpl<action::b, action::c>()} //, ...
}

, чтобы получить необходимый экземпляр во время выполнения. Однако это может привести к сотням неиспользованных экземпляров WorkerImpl<...>, что выглядит еще хуже. Идеальным было бы что-то вроде этой карты, но только сопоставленное с аргументами шаблона, то есть отображение строки в пакет типа / параметра. Но я не могу придумать, как это сделать. Существует ли шаблон / constexpr или какой-либо другой способ добиться этого или чего-то подобного, или я застрял на необходимости писать потенциально сотни избыточных операторов case? Или, может быть, мой дизайн кода плохой (хотя я бы не стал его менять, так как он в основном реализован)?

...