Автоматизированный вызов функций класса stati c C ++ 11 - PullRequest
0 голосов
/ 27 апреля 2020

Я работаю над проектом, выполняемым на микроконтроллере ESP32 (c ++ 11), и я хотел бы реализовать метод класса, который мог бы использовать ссылки на классы (не экземпляры этих классов) в качестве аргументов для выполнения stati c методы этих классов.

Мне удается реализовать следующее рабочее решение:

#include <iostream>

    class Model
{
public:
    static void foo()
    {
        std::cout << "Model.foo invoked" << std::endl;
    };
};

class ModelA: public Model
{
public:
    static void foo()
    {
        std::cout << "ModelA.foo invoked" << std::endl;
    };
};

class ModelB: public Model
{
public:
    static void foo()
    {
        std::cout << "ModelB.foo invoked" << std::endl;
    };
};


class Manager
{
public:

    template <class T = Model>
    void callFoo()
    {
        T::foo();
    }

    template<class T = Model, class ... args>
    void setup()
    {
       callFoo<T>();
       callFoo<args...>();
    }

};


int main()
{

    Manager manager;
    manager.setup<ModelA, ModelB>();

    return 0;
}

Вывод соответствует ожидаемому результату:

ModelA. Вызван foo

Вызван ModelB.foo

Но у меня такое ощущение, что этот подход в лучшем случае плохой хак ...

Есть ли у кого-то лучший способ реализовать это (в идеале без использования шаблона)?

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

Винсент.

Ответы [ 2 ]

1 голос
/ 27 апреля 2020

Если вы хотите отправить функции-члены stati c любого типа на основе ссылок этого типа, вы можете легко сделать это (слегка) злоупотребив выводом параметра шаблона функции:

template <typename T>
void call(T const& = *static_cast<T const*>(nullptr)) {
  T::foo();
}

struct Magic {
  static void foo() {}
};
struct MoreMagic {
  static void foo() {}
};

int main() {
  call<Magic>();
  call(MoreMagic());
  MoreMagic m;
  call(m);
}
0 голосов
/ 27 апреля 2020

Вы хотите использовать классы типов в качестве параметров. В настоящее время недоступно в "C ++".

Тем не менее, для вашего конкретного случая c, так как все методы stati c имеют одинаковый прототип функции или сигнатуру функции, вы можете сделать несколько обходных путей.

Во-первых, измените каждый метод stati c на виртуальный метод:

#include <iostream>

class Model
{
  public:
    virtual Foo(void* Args)
    {
      str::cout << "method Model.DoFoo( ) invoked. << std::endln;
    } // DoFoo

}; // class Model

class ModelA: Model
{
  public:
    virtual Foo(void* Args)
    {
      str::cout << "method ModelA.DoFoo( ) invoked. << std::endln;
    } // DoFoo

}; // class ModelA

class ModelB: Model
{
  public:
    virtual Foo(void* Args) override
    {
      str::cout << "method ModelB.DoFoo( ) invoked << std::endln;
  } // DoFoo

}; // class ModelB

Во-вторых, добавьте локальную функцию, а не метод, чтобы сгенерировать в результате экземпляр каждого класса:

 Model* ModelFactory( )
 {
   Model* M = new Model ( );
   return M;
 } // ModelFactory

 Model* ModelAFactory( )
 {
   Model* M = new ModelA( );
   return M;
 } // ModelFactory

 Model* ModelBFactory( )
 {
   Model* M = new ModelB ( );
   return M;
 } // ModelFactory

Три, ваш класс Manager, вместо параметров "variadi c" или "...", вы добавите вектор как один параметр, чтобы хранить ссылки на эти фабричные функции.

И параметр для хранения этого вектора.

#include <vector>

typedef
   Model* (*Factory) (void* Args);

class Manager
{
  public:
     std::vector<Factory>* Factories;

    void setup(std::vector<Factory>* AFactories)
    {
      this.Factories = AFactories;
    } // setup

} ; // class Manager

Обратите внимание, что фабрики работают как параметры классов типов.

Four, метод класса Manager для извлечения каждого изготовить из вектора, выполнить его, сгенерировать экземпляр, вызвать виртуальный метод замены, а затем утилизировать экземпляр.

class Manager
{
  public:
     std::vector<Factory>* Factories;

    void setup(std::vector<Factory>* AFactories)
    {
      this.Factories = AFactories;
    } // setup

    void run(void* Args)
    {
      for (Factory EachFactory : this.Factories)
      {
         Model* M = EachFactory( );
           M->Foo(Args);
         delete M;
      } // for
    } // void

} ; // class Manager

Пять, собрать пример:

int main( )
{
  Manager* M = new Manager( );

  // prepare compiletime list of classes
  std::vector<Factory>* Factories =
    new std::vector<Factory>*(2);

  Factories->insert(&ModelAFactory);
  Factories->insert(&ModelBFactory);

  // assign list to Manager
  M->setup(Factories);

  // execute each class method
  // with same parameters
  M->run( nullptr );

  // drop list
  delete Factories ( );

  delete M;
} // main

Ваш Model класс и подклассы могут иметь другие операции, вообще не связанные и все еще не конфликтующие, с заменой методов static на методы virtual.

Обратите внимание, что более новые версии стандарта C ++ могут делать нечто подобное с концепциями, и variadi c шаблоны аргументов.

...