使用可变参数模板的广播者/侦听器模式

问题描述 投票:0回答:1

我正在尝试使用可变参数模板实现某种广播者/侦听器模式:

template <typename... Args>
class WithListeners {
public:
    class Listener {
    public:
        virtual void operator()(Args&&... args) = 0;
    };
private:
    std::list<std::shared_ptr<Listener>> listeners;
public:
    void addListener(std::shared_ptr<Listener> l) {
        if (std::find(listeners.begin(), listeners.end(), l) == listeners.end())
            listeners.push_back(l);
    }
    void removeListener(std::shared_ptr<Listener> l) {
        listeners.remove(l);
    }
    void callListeners(Args&&... args) const {
        for (auto l : listeners) {
            if (l) (*l)(std::forward<Args>(args)...);
        }
    }
};

事实是我可以用<>编译,但不能用<int>编译。因此,例如,它无法编译:

class MyClassWithListener : public WithListeners<int>::Listener{
public:
    virtual void operator()(int value) override {
        //my handling code
    }
};

它说带有覆盖说明符的函数不会覆盖任何基类方法。

c++ variadic-templates
1个回答
1
投票

您可能认为您的operator()使用了完美的转发功能,但事实并非如此。在考虑Args...方法时,operator()模板参数已完全解析,因此它仅将所有参数用作常规RValue引用。

因此,您的替代项需要执行相同的操作:

class MyClassWithListener : public WithListeners<int>::Listener{
public:
    virtual void operator()(int&& value) override {
        //my handling code
    }
};

在这种情况下,最好只使用简单的参数:

template <typename... Args>
class WithListeners {
public:
    class Listener {
    public:
      virtual void operator()(Args... args) = 0;
    };

    void callListeners(Args... args) const {
        for (auto l : listeners) {
            if (l) (*l)(std::move(args)...);
        }
    }
};

因为您仍然可以完全定义侦听器的参数:

class MyClassWithListener : public WithListeners<const int&>::Listener{
public:
    virtual void operator()(const int& value) override {
        //my handling code
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.