从一个函数和某些类型说明符定义整个派生 class 的宏?

macro that defines entire derived class from one function and certain type specifiers?

我有一个 class 调用系统。系统采用一些对象管理器并以某种方式更改其中的所有对象。

例如,可能有一个系统在 imageManager 中绘制所有图像。

每个派生的 class 的工作方式有点像这样(伪代码):

class someChildClass : public System{
private:
     someObjectManager &mang1; //these are used by the update method.
     someOtherObjectManager &mang2;//the update method changes these somehow
public:
     someChildClass(someObjectManager &mang1, someObjectManager &mang2)
     :mang1(mang1),mang2(mang2){
     }
     virtual void update(){
     //this is pure virtual in the System base class.
     //Do something with the managers here
     }
}

我觉得什么都写,但更新方法是浪费时间和错误来源。我想写一个宏,基本上使 class 像这样:

QUICKSYSTEM(thisIsTheSystemName, someObjectManager, mang1, someOtherObjectManager, mang2, ... (infinite possible Managers. So a variadic macro?)){
//this is the update function
}
}//this is the end braked for the class declaration. Its ugly but I dont know how I could do the function differently? 

好吧,我在制作宏时遇到了一些问题。一切正常,直到我需要将可变参数拆分为名称和类型。我不知道现在这是否可能,因为我不能轻易地在参数中来回切换或对它们应用一个简单的步骤来确保每个 2nd 都是变量的名称。我可以忽略名称的可能性,只使用具有某种自动命名的类型(manager1、manager2、manager3 或类似名称)。

如果使用宏不可能做到这一点,有什么更好的方法可以避免错误并缩短构造函数和 class 声明部分的时间?

是的,宏确实、真的不是执行此操作的方法。 C++ 有模板,它遵循 C++ 语法并支持 C++ 表达式。宏使用它们自己的预处理器语言,这几乎完全不了解 C++。

您还需要阅读一些关于 std::tuple 的内容。处理所有这些名字的经理将相当棘手。元组是标准解决方案。 managers.get<0>managers.get<someObjectManager> 都有效。

可变参数模板是您在这里需要的工具:

#include <iostream>
#include <tuple>
#include <functional>

struct System { void virtual update() = 0; };
template<class... Managers>
struct ManagedSystem : System
{
    std::function<void(Managers&...)> _update;
    std::tuple<Managers&...>          _managers;

    template<class F>
    ManagedSystem(F update, Managers&... managers) : _update(update), _managers(managers...) {}

    void update() override { _update(std::get<Managers&>(_managers)...); }
};

int main()
{
    int n = 0;
    double d = 3.14;
    auto reset = [](int& a, double& d) { a = 0; d = 0.0; };
    ManagedSystem<int, double> ms{reset, n, d};
    ms.update();
    std::cout << "n = " << n << ", d = " << d << "\n";
    // n = 0, d = 0
}

想法是定义一个模板化的-class (ManagedSystem),将多种管理器类型作为模板参数。 class 继承自 System 并提供了一个构造函数:

  1. 一个更新函子,
  2. 以及对管理器的引用,其类型由通过 class.
  3. 的模板参数定义

上述管理器在 std::tuple 内部注册并且(有一点 parameter pack magic 馈送到更新函子。

从那里,您可以通过提供更新函数和类型列表来定义从 System 继承的 class。这避免了使用丑陋和类型不安全的宏,转而使用同样丑陋但类型字符串的模板 ;)