Как получить ноль или более аргументов для std:: функции, используемой в качестве значения в std::map?

#c #lambda #stdmap #std-function

#c #лямбда #stdmap #std-функция

Вопрос:

У меня есть класс Engine, в котором есть элемент типа std::map, который сопоставляет перечисления функциям-членам. Я могу сопоставить перечисление со всеми функциями, если количество аргументов функций одинаково.

 enum STATE { OFF, ON, HIBERNATE, RESTART };
enum RETCODE { SUCCESS, FAIL, UNKNOWN, OUTOFBOUND };

class Engine
{
    Engine();
    RETCODE StateOn(double val);
    RETCODE StateOff(double val);
    RETCODE StateHibernate(double val);
    RETCODE StateRestart(double val);
private:
    const std::map<STATE, std::function<RETCODE(double)>> Map_State_FnPtr;
};

Engine::Engine() : Map_State_FnPtr {
        { STATE::ON, [=](double val) {return StateOn(val); } },
        { STATE::OFF, [=](double val) {return StateOff(val); } },
        { STATE::HIBERNATE, [=](double val) {return StateHibernate(val); } },
        { STATE::RESTART, [=](double val) {return StateRestart(val); } }
    }
{
    // c'tor body
}
  

Но у меня есть сценарий, в котором некоторые функции могут иметь ноль или несколько аргументов.
Как мне объявить и сконструировать переменную map в таком сценарии?

 class Engine
{
    Engine();
    RETCODE StateOn();                                              // No arguments
    RETCODE StateOff(double val);                                   // 1 argument
    RETCODE StateHibernate(double val, const std::string amp; data);   // Multiple arguments
    RETCODE StateRestart(double val);
private:
    const std::unordered_map<STATE, std::function<RETCODE()>> Map_State_FnPtr; // What should be the declaration?
};
  

Есть другие предложения для этого сценария?
Пожалуйста, помогите.

Ответ №1:

Вы всегда можете игнорировать параметры

 {
    { STATE::ON, [=](double, const std::string amp;) {return StateOn(); } },
    { STATE::OFF, [=](double val, const std::string amp;) {return StateOff(val); } },
    { STATE::HIBERNATE, [=](double val, const std::string amp; data) {return StateHibernate(val, data); } },
    { STATE::RESTART, [=](double val, const std::string amp;) {return StateRestart(val); } }
}
  

Ответ №2:

Как мне объявить и сконструировать переменную map в таком сценарии?

Это невозможно с std::function . Этот шаблон предлагает определенное количество стираний типов, поскольку он может быть сконструирован с указателями на функции, лямбдами с отслеживанием состояния или указателями на функции-члены, но существует инвариант, то есть сигнатура типа функции, которую вы аппроксимируете с помощью std::function экземпляра.

Вместо этого вы могли бы определить пользовательский агрегат, который воплощает возможные варианты списков параметров, например

 struct StateParams {
    double val;
    std::string data;
};
  

затем измените сигнатуры вашей функции на

 RETCODE StateOn(const StateParamsamp;);
RETCODE StateHibernate(const StateParamsamp;);
// ...
  

и std::map может иметь value_type std::function<RETCODE(const StatemParamsamp;> .

Комментарии:

1. Если не с помощью std::function, как я могу объявить / сконструировать std::map в соответствии со следующим требованием. Приветствуются другие альтернативные предложения.

2. Вы могли бы попробовать использовать std::any и any_cast , если у вас есть C 17, но для этого требуется дополнительное поле для запоминания фактической подписи, и это также довольно небезопасно. Простого способа сделать это нет.