Информация об изменениях

Сообщение Re: Не очень понимаю, как на модных плюсиках сделать такую ш от 21.09.2023 20:27

Изменено 21.09.2023 20:31 rg45

Re: Не очень понимаю, как на модных плюсиках сделать такую шляпу
Здравствуйте, Marty, Вы писали:

M>Здравствуйте!


M>Есть интерфейс, с какими-то виртуальными методами. Есть какие-то реализации этого интерфейса.


M>Есть отдельная реализация, которая хранит в себе указатели на несколько реализаций того же интерфейса, и каждый вызов метода через эту мульти реализацию должен вызывать этот метод через все хранящиеся указатели на другие реализации.


M>При этом, если метод что-то возвращает, то за результат берём вызов через первый хранящийся указатель на интерфейс, а остальное игнорируем


Ну, вот как-то так. Есть небольшая шероховатость — первый обработчик всегда вызывается последним (потому, что именно его результат возвращается). Но эта мелочь легко устраняется добавлением еще одного метода делегирования:

http://coliru.stacked-crooked.com/a/3b8ca43b7a409e5f

#include <concepts>
#include <iostream>
#include <memory>
#include <vector>

struct IDelegationTest
{

   virtual bool getter() = 0;
   virtual bool setter(bool b) = 0;
   virtual void jobImpl(bool b, int i) = 0;
   virtual void jobImpl(bool b, int i, const std::string& s) = 0;
   virtual int jobImpl2(bool b, int i) = 0;

};

struct DelegationTestImpl : public IDelegationTest
{
   int n = 0;

   DelegationTestImpl() = default;
   explicit DelegationTestImpl(int n) : n(n) {}

   virtual bool getter() override
   {
      std::cout << "DelegationTestImpl::getter(), n: " << n << "\n";
      return true;
   }

   virtual bool setter(bool b) override
   {
      std::cout << "DelegationTestImpl::setter(bool b), b: " << b << ", n: " << n << "\n";
      return true;
   }

   virtual void jobImpl(bool b, int i) override
   {
      std::cout << "DelegationTestImpl::jobImpl(bool b, int i), b: " << b << ", i: " << i << ", n: " << n << "\n";
   }

   virtual void jobImpl(bool b, int i, const std::string& s) override
   {
      std::cout << "DelegationTestImpl::jobImpl(bool b, int i), b: " << b << ", i: " << i << ", s: " << s << ", n: " << n << "\n";
   }

   virtual int jobImpl2(bool b, int i) override
   {
      std::cout << "DelegationTestImpl::jobImpl2(bool b, int i), b: " << b << ", i: " << i << ", n: " << n << "\n";
      return n;
   }

};

template <typename F>
concept DelegatorAgent = requires (F f, IDelegationTest& t)
{
   f(t);
};

template <typename T>
concept DelegationTestPtr = std::convertible_to<std::decay_t<T>, std::shared_ptr<IDelegationTest>>;

class Delegator : public IDelegationTest
{
   template <DelegatorAgent F>
   decltype(auto) doDelegate(F&& f)
   {
      for (auto&& impl : m_tail)
      {
         f(*impl);
      }
      return f(*m_head);
   }

public:

   template <DelegationTestPtr T, DelegationTestPtr...X>
   explicit Delegator(T&& head, X&&...tail)
      : m_head(std::forward<T>(head)), m_tail{ std::forward<X>(tail)...} {}

   bool getter() override { return doDelegate([&](IDelegationTest& t){ return t.getter(); }); }
   bool setter(bool b) override { return doDelegate([&](IDelegationTest& t) { return t.setter(b); }); }
   void jobImpl(bool b, int i) override { doDelegate([&](IDelegationTest& t) { t.jobImpl(b, i); }); }
   void jobImpl(bool b, int i, const std::string& s) override { doDelegate([&](IDelegationTest& t) { t.jobImpl(b, i, s); }); }
   int jobImpl2(bool b, int i) override { return doDelegate([&](IDelegationTest& t) { return t.jobImpl2(b, i); }); }

private:

   using ImplPtr = std::shared_ptr<IDelegationTest>;

   const ImplPtr m_head;
   const std::vector<ImplPtr> m_tail;
};

int main()
{
   Delegator delegator {
      std::make_shared<DelegationTestImpl>(1),
      std::make_shared<DelegationTestImpl>(2),
      std::make_shared<DelegationTestImpl>(3),
   };

   delegator.getter();
   delegator.setter(true);
   delegator.jobImpl(false, 3);
   delegator.jobImpl2(true, 5);
}
Re: Не очень понимаю, как на модных плюсиках сделать такую ш
Здравствуйте, Marty, Вы писали:

M>Здравствуйте!


M>Есть интерфейс, с какими-то виртуальными методами. Есть какие-то реализации этого интерфейса.


M>Есть отдельная реализация, которая хранит в себе указатели на несколько реализаций того же интерфейса, и каждый вызов метода через эту мульти реализацию должен вызывать этот метод через все хранящиеся указатели на другие реализации.


M>При этом, если метод что-то возвращает, то за результат берём вызов через первый хранящийся указатель на интерфейс, а остальное игнорируем


Ну, вот как-то так. Без явного указания прототипа с перегрузками, как ты и хотел. Единственная небольшая шероховатость — первый обработчик всегда вызывается последним (потому, что именно его результат возвращается). Но эта мелочь легко устраняется добавлением еще одного метода делегирования (аналогичного doDelegate):

http://coliru.stacked-crooked.com/a/3b8ca43b7a409e5f

#include <concepts>
#include <iostream>
#include <memory>
#include <vector>

struct IDelegationTest
{

   virtual bool getter() = 0;
   virtual bool setter(bool b) = 0;
   virtual void jobImpl(bool b, int i) = 0;
   virtual void jobImpl(bool b, int i, const std::string& s) = 0;
   virtual int jobImpl2(bool b, int i) = 0;

};

struct DelegationTestImpl : public IDelegationTest
{
   int n = 0;

   DelegationTestImpl() = default;
   explicit DelegationTestImpl(int n) : n(n) {}

   virtual bool getter() override
   {
      std::cout << "DelegationTestImpl::getter(), n: " << n << "\n";
      return true;
   }

   virtual bool setter(bool b) override
   {
      std::cout << "DelegationTestImpl::setter(bool b), b: " << b << ", n: " << n << "\n";
      return true;
   }

   virtual void jobImpl(bool b, int i) override
   {
      std::cout << "DelegationTestImpl::jobImpl(bool b, int i), b: " << b << ", i: " << i << ", n: " << n << "\n";
   }

   virtual void jobImpl(bool b, int i, const std::string& s) override
   {
      std::cout << "DelegationTestImpl::jobImpl(bool b, int i), b: " << b << ", i: " << i << ", s: " << s << ", n: " << n << "\n";
   }

   virtual int jobImpl2(bool b, int i) override
   {
      std::cout << "DelegationTestImpl::jobImpl2(bool b, int i), b: " << b << ", i: " << i << ", n: " << n << "\n";
      return n;
   }

};

template <typename F>
concept DelegatorAgent = requires (F f, IDelegationTest& t)
{
   f(t);
};

template <typename T>
concept DelegationTestPtr = std::convertible_to<std::decay_t<T>, std::shared_ptr<IDelegationTest>>;

class Delegator : public IDelegationTest
{
   template <DelegatorAgent F>
   decltype(auto) doDelegate(F&& f)
   {
      for (auto&& impl : m_tail)
      {
         f(*impl);
      }
      return f(*m_head);
   }

public:

   template <DelegationTestPtr T, DelegationTestPtr...X>
   explicit Delegator(T&& head, X&&...tail)
      : m_head(std::forward<T>(head)), m_tail{ std::forward<X>(tail)...} {}

   bool getter() override { return doDelegate([&](IDelegationTest& t){ return t.getter(); }); }
   bool setter(bool b) override { return doDelegate([&](IDelegationTest& t) { return t.setter(b); }); }
   void jobImpl(bool b, int i) override { doDelegate([&](IDelegationTest& t) { t.jobImpl(b, i); }); }
   void jobImpl(bool b, int i, const std::string& s) override { doDelegate([&](IDelegationTest& t) { t.jobImpl(b, i, s); }); }
   int jobImpl2(bool b, int i) override { return doDelegate([&](IDelegationTest& t) { return t.jobImpl2(b, i); }); }

private:

   using ImplPtr = std::shared_ptr<IDelegationTest>;

   const ImplPtr m_head;
   const std::vector<ImplPtr> m_tail;
};

int main()
{
   Delegator delegator {
      std::make_shared<DelegationTestImpl>(1),
      std::make_shared<DelegationTestImpl>(2),
      std::make_shared<DelegationTestImpl>(3),
   };

   delegator.getter();
   delegator.setter(true);
   delegator.jobImpl(false, 3);
   delegator.jobImpl2(true, 5);
}