Шаблон Broadcaster / Listener с использованием шаблонов variadi c - PullRequest
0 голосов
/ 20 февраля 2020

Я пытаюсь реализовать своего рода шаблон Broadcaster / Listener, используя шаблон variadi c:

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
    }
};

Это говорит о том, что функция со спецификатором переопределения не переопределяет любой метод базового класса.

1 Ответ

2 голосов
/ 20 февраля 2020

Вы можете подумать, что ваш operator() использует идеальную пересылку, но это не так. Аргумент шаблона Args... полностью разрешается к тому времени, когда рассматривается метод operator(), поэтому он просто принимает все аргументы как обычные ссылки RValue.

Из-за этого переопределение должно делать то же самое :

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

Вы бы лучше обслужили просто go с прямыми аргументами в этом случае:

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
    }
};
...