1

我正在尝试以一种可以极大地简化我的开发进度的方式使用 C++ 中的预处理器!我有一个非常简单的问题,我在使用常规 C++ 类的同时使用 C API 库。这个库基于回调/事件,我只能提供函数(而不是方法)。因此,我有一个重复的模式,为每个事件声明一个静态和非静态函数:

public: // Here is the static method which is required
    static inline Vector StaticEventClickLeft(Vector vec) { return globalClass->EventClickLeft(vec); }
private: // And here is the method (i.e non-static)
    Vector EventClickLeft(Vector vec);

我想创建一个宏,在一行中定义这两个。它会使我的标题的大小至少减少十倍!这是我最接近的尝试(但还远远不够):

#define DECL_EVENT(func, ret, ...) \
    public: static inline ret S ## Event ## func(__VA_ARGS__) { return globalClass->Event ## func(__VA_ARGS__); } \
    private: ret Event ## func(__VA_ARGS__);

如果我像这样使用这个宏DECL_EVENT(ClickLeft, Vector, Vector vec)。这将是输出:

public: static inline Vector SEventClickLeft(Vector vec) { return globalClass->EventClickLeft(Vector vec); }
private: Vector EventClickLeft(Vector vec);

你可以清楚地看到问题所在。静态函数调用该方法并提供参数的类型以及名称。由于指定了类型,因此会导致编译器错误;include/plugin.h:95:2: error: expected primary-expression before ‘TOKEN’ token .

那么我该如何解决呢?必须有一些解决方案,我相信一些宏观专家可以提供一些帮助!

4

2 回答 2

1

首先,在您的类型周围放置括号,以便预处理器可以解析它。所以你会像这样调用 DECL_EVENT:

DECL_EVENT(ClickLeft, Vector, (Vector) vec)

以下是一些宏,它们将检索类型并剥离类型(您需要命名它们,我离开命名空间只是为了演示):

#define EAT(...)
#define REM(...) __VA_ARGS__
#define STRIP(x) EAT x
#define PAIR(x) REM x

这些宏是这样工作的。当您编写STRIP((Vector) vec)时,它将扩展为vec. 当你写PAIR((Vector) vec)它时,它会扩展为Vector vec. 接下来,您要做的是将这些宏应用于传入的每个参数,所以这里有一个简单的APPLY宏,可以让您对最多 8 个参数执行此操作:

/* This counts the number of args */
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)

/* This will let macros expand before concating them */
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

/* This will call a macro on each argument passed in */
#define APPLY(macro, ...) CAT(APPLY_, NARGS(__VA_ARGS__))(macro, __VA_ARGS__)
#define APPLY_1(m, x1) m(x1)
#define APPLY_2(m, x1, x2) m(x1), m(x2)
#define APPLY_3(m, x1, x2, x3) m(x1), m(x2), m(x3)
#define APPLY_4(m, x1, x2, x3, x4) m(x1), m(x2), m(x3), m(x4)
#define APPLY_5(m, x1, x2, x3, x4, x5) m(x1), m(x2), m(x3), m(x4), m(x5)
#define APPLY_6(m, x1, x2, x3, x4, x5, x6) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6)
#define APPLY_7(m, x1, x2, x3, x4, x5, x6, x7) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7)
#define APPLY_8(m, x1, x2, x3, x4, x5, x6, x7, x8) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8)

现在介绍如何编写DECL_EVENT宏:

#define DECL_EVENT(func, ret, ...) \
public: static inline ret S ## Event ## func(APPLY(PAIR, __VA_ARGS__)) { return globalClass->Event ## func(APPLY(STRIP, __VA_ARGS__)); } \
private: ret Event ## func(APPLY(PAIR, __VA_ARGS__));

注意:这可能在 MSVC 中不起作用,因为它们有一个错误的预处理器(尽管有解决方法)。

于 2012-05-08T22:54:12.487 回答
1

试图在 C++ 中滥用预处理器通常是个坏主意。

有什么理由不能boost::signal满足您的需求吗?

作为奖励,您可以使用std::function(或者boost::function如果您被困在 C++03 领域)将您的成员函数绑定到对象实例并摆脱全局。

于 2012-05-08T21:37:57.287 回答