LINUX.ORG.RU

Избранные сообщения igniperch

С++ Помогите избавиться от дублирования однотипного кода.

Форум — Development

Всем доброго времени суток. Возникла проблема (точнее, понимание того, что в одном месте код фактически N раз дублируется). Приведенный далее код просто поясняет проблему и даже не компилировался.

Дано: 1. Интерфейсный класс с тремя (на самом деле, их значительно больше) методами разных сигнатур.

// Интерфейсный класс родителя.
class IParent
{
public:
   virtual bool fu0() = 0;
   virtual bool fu1(const std::string &) = 0;
   virtual std::string fu2() = 0;
   virtual ~IParent() = 0;
};

2. Потомки с конкретными реализациями этих методов. Понятно, что потомков может быть сколько угодно.

class CChild0 : public IParent
{
public:
   virtual bool fu0() override
   {
      // Что-то делаем.
   }
   virtual bool fu1(const std::string & param) override
   {
     // Опять что-то много делаем.
   }
   virtual std::string fu2() override
   {
      // И тут делаем.
   }
};

3. Супер-класс, который хранит в себе через указатели на базовый класс потомков в мапе.

class CSuperHandler
{
private:
   // Мапа для хранения потомков через указатель на родителя. Ключ - далее id.
   std::map<int, std::unique_ptr<IParent>> mMap;
public:
   CSuperHandler()
   {
      //Заполнение мапы может быть не только тут.
      mMap.insert(std::make_pair(0, std::unique_ptr<IParent>(new CChild0)));
      mMap.insert(std::make_pair(1, std::unique_ptr<IParent>(new CChild1)));
      mMap.insert(std::make_pair(2, std::unique_ptr<IParent>(new CChild2)));
   }
   
   // Должен запускать метод fu0 если найден потомок.
   bool SuperFu0(const int id)
   {
      auto it = mMap.find(id);
      bool returnValue = false;
      if(it != mMap.end())
      {
         returnValue = it->second->fu0();
      }
      else
      {
         std::cout << "ID not found.";
      }
      return returnValue;
   }
   
   // Должен запускать метод fu1 если найден потомок.
   bool SuperFu1(const int id, const std::string & param)
   {
      auto it = mMap.find(id);
      bool returnValue = false;
      if(it != mMap.end())
      {
         returnValue = it->second->fu1(param);
      }
      else
      {
         std::cout << "ID not found.";
      }
      return returnValue;
   }
   
   // Должен запускать метод fu2 если найден потомок.
   std::string SuperFu2(const int id)
   {
      auto it = mMap.find(id);
      std::string returnValue = "";
      if(it != mMap.end())
      {
         returnValue = it->second->fu2();
      }
      else
      {
         std::cout << "ID not found.";
      }
      return returnValue;
   }
};

Собственно, что проблема в том, что методы SuperFu0, SuperFu1,SuperFu2 (а на самом деле, их много) имеют практически одинаковое содержимое: проверяют есть ли нужный id и запускают у соотвествующего потомка метод, результат которого возвращают. Пока я не придумал как можно это дело оптимизировать.

Хотелось бы, конечно, иметь что-то вроде:

template<typename T, typename... Args>
T doAction(int id, std::function<T(const Args & ... args)> fu, const Args & ... args)
{
  auto it = mMap.find(id);
  T returnValue;
  if(it != mMap.end())
  {
    returnValue = it->second->fu(args...);
  }
  else
  {
    std::cout << "ID not found.";
  }
  return returnValue;
} 

Но мы же не можем передать туда указатель на метод объекта, которого при вызове шаблонного метода еще не знаем (он внутри по id определяется). В общем, если кто-то подскажет какое-то удачное решение - буду очень рад. Спасибо!

 

igniperch
()