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

时间:2018-04-23 09:26:22

标签: c++ variadic variadic-macros

我有一个叫做系统的类。系统需要一些对象管理器并以某种方式更改其中的所有对象。

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

每个派生类的工作方式都与此类似(伪代码):

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

我想写一切,但更新方法是浪费时间和错误的来源。我想写一个宏,基本上像这样生成一个类:

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? 
好吧,我在制作宏时遇到了一些问题。一切正常,直到我需要将可变参数分成名称和类型。我现在不知道这是否可能,因为我不能轻易地在论证中来回或对它们应用一个简单的步骤,以确保每一个都是变量的名称。我可以省略名称的可能性,只是让类型具有某种自动命名(manager1,manager2,manager3或类似的东西)。

如果使用宏不可能,那么在构造函数和类声明部分中避免错误和减少时间的更好方法是什么?

2 个答案:

答案 0 :(得分:3)

是的,宏真的,真的不是这样做的方式。 C ++有模板,它遵循C ++语法并支持C ++表达式。宏使用自己的预处理器语言,几乎完全不知道C ++。

你也想在std::tuple上阅读一下。处理所有那些拥有这些名字的经理人会相当棘手。元组是标准的解决方案。 managers.get<0>managers.get<someObjectManager>都有效。

答案 1 :(得分:2)

Variadic模板是您需要的工具:

#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
}

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

  1. 更新仿函数,
  2. 以及对类型由定义的经理的引用类的模板参数。
  3. 所述经理在std::tuple内部注册,并且(有一点parameter pack magic被提供给更新仿函数。

    从那里,您可以通过提供更新功能和类型列表来定义System中的继承类。这避免了使用丑陋和类型不安全的宏来支持丑陋但类型字符串模板;)