std::функция и std::переадресация с различными шаблонами

#c #c 17 #variadic-templates

Вопрос:

Недавно я читал о вариативных шаблонах и, основываясь на примере, который я видел в Интернете, пытался реализовать базовую систему событий. До сих пор это, кажется, работает нормально, но я пытался пойти дальше и разрешить передачу N аргументов функции / обратного вызова обработчика событий, к сожалению, ошибка сборки, которую я получаю, заключается в следующем, и я не уверен, что я делаю неправильно. Я просмотрел аналогичные исходные коды, но все еще не могу понять, в чем проблема.

 D:Developmentlabc-cppEventEmitter3srcmain.cpp:30:68: error: parameter packs not expanded with '...':  return std::any_castlt;std::functionlt;R(Args)gt;gt;(eventCallback)(std::forwardlt;Argsgt;(args)...);  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~  D:Developmentlabc-cppEventEmitter3srcmain.cpp:30:68: note: 'Args'  Build finished with error(s).  

Вот что у меня есть до сих пор, если вы удалите ... систему событий, она отлично работает для 2 зарегистрированных событий main .

 #include lt;anygt; #include lt;stringgt; #include lt;iostreamgt; #include lt;functionalgt; #include lt;unordered_mapgt;  class EventEmitter {  private:  std::unordered_maplt;std::string, std::anygt; events;  public:  EventEmitter() {}   void on(const std::string amp;eventName, const std::any amp;eventCallback)  {  events[eventName] = eventCallback;  }   template lt;typename Rgt;  R emit(const std::string amp;eventName)  {  const std::any amp;eventCallback = events[eventName];  return std::any_castlt;std::functionlt;R(void)gt;gt;(eventCallback)();  }   template lt;typename R, typename... Argsgt;  R emit(const std::string amp;eventName, Args amp;amp;...args)  {  const std::any amp;eventCallback = events[eventName];  return std::any_castlt;std::functionlt;R(Args)gt;gt;(eventCallback)(std::forwardlt;Argsgt;(args)...);  }   virtual ~EventEmitter() {} };  int fun1() {  std::cout lt;lt; "fun1" lt;lt; std::endl;  return 1; }  double fun2(int i) {  std::cout lt;lt; "fun2" lt;lt; std::endl;  return double(i); }  double fun3(int x, int y) {  std::cout lt;lt; "fun3" lt;lt; std::endl;  return double(x   y); }  int main(int argc, char *argv[]) {  EventEmitter e;   e.on("fun1", std::functionlt;int(void)gt;(fun1));  e.on("fun2", std::functionlt;double(int)gt;(fun2));     e.emitlt;intgt;("fun1");  e.emitlt;double, intgt;("fun2", 1);    // Variadic would have been handy right here I guess?  // e.on("fun3", std::functionlt;double(int, int)gt;(fun3));   // e.emitlt;double, intgt;("fun3", 1, 2);    return 0; }  

Как я могу это исправить?

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

1. на самом деле вам не нужна первая перегрузка emit , так как пакет параметров также может быть пустым, поэтому emit with Args... также будет обрабатывать случай, когда нет аргументов

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

3. @SergeyKolesnik да, вы правы. Это осталось до того, как я добавил вариативные шаблоны.

Ответ №1:

Что ж, вам нужно его расширить.

 return std::any_castlt;std::functionlt;R(Args...)gt;gt;(eventCallback)(std::forwardlt;Argsgt;(args)...);  ^^^^^^^  

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

1. Более конкретно, его необходимо расширять один раз для каждого использования. Поскольку вы дважды ссылаетесь на пакет параметров, его необходимо дважды расширить.

2. О боже мой… Наверное, мне нужна новая пара глаз… большое вам спасибо! Я приму это, как только таймер позволит.