【问题标题】:Automated call to class static functions C++11自动调用类静态函数 C++11
【发布时间】:2020-04-27 09:49:03
【问题描述】:

我正在开发一个在 ESP32 微控制器 (c++11) 上执行的项目,我想实现一个可以将类引用(不是这些类的实例)作为参数的类方法,以便执行静态这些类的方法。

我设法实施以下工作解决方案:

#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 调用

但我觉得这种方法充其量只是一个糟糕的黑客......

是否有人有更好的方法来实现这一点(最好不使用模板)?

提前谢谢你。

文森特。

【问题讨论】:

  • 我觉得这个设计有问题。您正在使用 Model 衍生物进行名称隐藏,并且整个类型层次结构在示例中没有多大意义。你到底想在这里做什么?
  • 嗨蒂莫,谢谢你的回答。你是对的,这种设计毫无疑问是有问题的 ;-) 在我的示例中它并不明确,但是从 Model 类继承的所有 Model 类都是单例的。我想在 Manager 类上实现一个 setup 方法,它可以采用任意数量的 Model 子类“类引用”(不是实例),并为每个引用调用 Model 的静态方法。
  • 我认为你所拥有的是你在 C++11 中能做到的最好的。使用 C++17,这有效:template&lt;typename... Models&gt; void setup() { (Models::foo(), ...); }
  • 目前还不清楚Model 类在这一切中的作用。当ModelAModelB 不派生自Model 以及Model 根本不存在时,该代码也可以正常工作。
  • 您好,Igor,感谢您抽出宝贵时间回答。我被c++11(微控制器环境)困在这里。实际项目中的模型类是模板单例。

标签: c++ c++11 static-methods


【解决方案1】:

如果您想根据该类型的引用分派任何类型的静态成员函数,您可以通过(稍微)滥用函数模板参数推断来轻松做到这一点:

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

【讨论】:

  • 感谢您的回答位掩码。可能是我错过了一些东西,但是这个解决方案,即使模板方法更加通用,也有点类似于我最初发布的那个没有?
  • 是的,区别在于您可以根据对完整类型的引用进行调度,而我丢弃了不必要的多态性。根据您的问题,您想根据引用的类型调用静态函数,这正是它的作用。也许我误解了你想要完成的事情?是否要根据多态对象的运行时类型进行调度?
  • ...但是,如果您使用的是微控制器,您可能希望轻松处理多态...
  • 你好位掩码。明白了,你是对的,这里不需要多态。再次感谢您。
【解决方案2】:

您想使用类型类作为参数。目前在“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 类,而不是“variadic”或“...”参数,您将添加一个向量作为单个参数,以存储对这些工厂函数的引用。

还有一个用于存储该向量的参数。

#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

请注意,工厂作为类型类参数工作。

四,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++ 标准可以对概念和可变参数模板执行类似的操作。

【讨论】:

  • 谢谢 umlcat。我想我理解你的解决方案,但我应该在我的帖子中提到 Model 是一个用于 ESP32 微控制器的小型“MVC 框架”的单例模板类。目标是在启动时调用每个模型单例的传统“getInstance”方法,然后在用户代码中显式调用它。感谢您的宝贵时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-16
  • 1970-01-01
相关资源
最近更新 更多