【问题标题】:std::function & std::forward with variadic templates带有可变参数模板的 std::function 和 std::forward
【发布时间】:2022-01-05 19:30:07
【问题描述】:

最近我正在阅读有关可变参数模板的内容,并且基于我在网上看到的一个示例,我试图实现一个基本的事件系统。到目前为止,它似乎工作正常,但我试图更进一步,允许将 N 个参数传递给事件处理函数/回调,不幸的是,我得到的构建错误如下,我不确定我做错了什么。我查看了类似的源代码,但仍然无法弄清楚问题所在。

D:\Development\lab\c-cpp\EventEmitter3\src\main.cpp:30:68: error: parameter packs not expanded with '...':
         return std::any_cast<std::function<R(Args)>>(eventCallback)(std::forward<Args>(args)...);
                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

D:\Development\lab\c-cpp\EventEmitter3\src\main.cpp:30:68: note:         'Args'

Build finished with error(s).

这是我目前所拥有的,如果您删除 ...,事件系统对于 main 中的 2 个注册事件可以正常工作。

#include <any>
#include <string>
#include <iostream>
#include <functional>
#include <unordered_map>

class EventEmitter
{

private:
    std::unordered_map<std::string, std::any> events;

public:
    EventEmitter() {}

    void on(const std::string &eventName, const std::any &eventCallback)
    {
        events[eventName] = eventCallback;
    }

    template <typename R>
    R emit(const std::string &eventName)
    {
        const std::any &eventCallback = events[eventName];
        return std::any_cast<std::function<R(void)>>(eventCallback)();
    }

    template <typename R, typename... Args>
    R emit(const std::string &eventName, Args &&...args)
    {
        const std::any &eventCallback = events[eventName];
        return std::any_cast<std::function<R(Args)>>(eventCallback)(std::forward<Args>(args)...);
    }

    virtual ~EventEmitter() {}
};

int fun1()
{
    std::cout << "fun1" << std::endl;
    return 1;
}

double fun2(int i)
{
    std::cout << "fun2" << std::endl;
    return double(i);
}

double fun3(int x, int y)
{
    std::cout << "fun3" << std::endl;
    return double(x + y);
}

int main(int argc, char *argv[])
{
    EventEmitter e;

    e.on("fun1", std::function<int(void)>(fun1));
    e.on("fun2", std::function<double(int)>(fun2));
    

    e.emit<int>("fun1");
    e.emit<double, int>("fun2", 1);
    
    // Variadic would have been handy right here I guess?
    // e.on("fun3", std::function<double(int, int)>(fun3)); 
    // e.emit<double, int>("fun3", 1, 2); 

    return 0;
}

我该如何解决这个问题?

【问题讨论】:

  • 您实际上不需要emit 的第一个重载,因为参数包也可以为空,因此emitArgs... 也将处理没有参数的情况
  • 虚拟析构函数在这里也没有任何意义,因为您不提供任何虚拟函数(并且模板函数不能是虚拟的)。仅当您拥有指向基类的指针时,运行时多态才需要虚拟析构函数。
  • @SergeyKolesnik 是的,你是对的。这是我添加可变参数模板之前的剩余部分。

标签: c++ c++17 variadic-templates


【解决方案1】:

嗯,你需要扩展它。

return std::any_cast<std::function<R(Args...)>>(eventCallback)(std::forward<Args>(args)...);
                                     ^^^^^^^

【讨论】:

  • 更具体地说,每次使用都需要扩展一次。由于您引用了两次参数包,因此需要对其进行两次扩展。
  • 天哪……我想我需要一双新眼睛……非常感谢!一旦计时器允许,我会接受。
猜你喜欢
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 2012-08-03
  • 2015-12-09
  • 1970-01-01
  • 2016-06-11
  • 2016-03-21
  • 2017-10-10
相关资源
最近更新 更多