Передача аргументов диспетчера C ++ - PullRequest
0 голосов
/ 12 декабря 2018

У меня есть простая структура диспетчера, которая не будет компилироваться и, честно говоря, я понятия не имею, почему.

Итак, я создал диспетчер, который вы можете привязать функцию к вызываемому обновлению, она будетвызвать статическую функцию-член invoke, которая разыменовывает экземпляр объекта и вызывает метод с простым std::ostream ref.

. По какой-то причине это не компилируется, но мне кажется, что это правильно.Компилятор не даст хорошего вывода: /

Заранее спасибо

#include <iostream>
#include <list>
#include <utility>

namespace trd {

  struct dispatcher {
    public:
      template<typename C, void(C::*M)(std::ostream & os) = C::update>
        static void invoke(void * instance, std::ostream & os) {
          (static_cast<C*>(instance)->*M)(os);
        }

      template<typename C, void(C::*M)(std::ostream & os) = &C::update>
        void bind(C * instance) {
          instances.push_back(std::make_pair(&invoke<C, M>, instance));
        }

      void operator () (std::ostream & os) {
        for (auto & instance : instances)
          (instance.first)(instance.second, os);
      }

    private:
      std::list<std::pair<void(*)(std::ostream & os), void *>> instances;
  };

}

struct test {
  public:
    void update(std::ostream & os) { os << "foo"; }
};

int main() {
  trd::dispatcher dp;

  test t;

  dp.bind(&t);

  dp(std::cout);

  return 0;
}

1 Ответ

0 голосов
/ 12 декабря 2018

Вы используете методы, а не функции, поэтому использование экземпляра как void - плохая практика, использование приведений в стиле C.

Вместо этого в C ++ есть std::function и лямбда-выражения:

namespace trd {

  struct dispatcher {
    public:
      template<typename C, void(C::*M)(std::ostream & os) = &C::update>
        void bind(C * instance) {
          instances.push_back([=](std::ostream & os){std::invoke(M, instance, os);});
        }

      void operator () (std::ostream & os) {
        for (auto & instance : instances)
          std::invoke(instance, os);
      }

    private:
      std::list<std::function<void(std::ostream & os)>> instances;
  };
}

Использование C ++ 17 для std::invoke.

...