1

開発の進行を大幅に容易にする方法で、C++のプリプロセッサを利用しようとしています。非常に単純な問題があります。通常のC++クラスを使用しながら、CAPIライブラリを使用しています。このライブラリはコールバック/イベントに基づいており、関数(メソッドではない)のみを提供できます。このため、イベントごとに静的関数と非静的関数を宣言するという繰り返しのパターンがあります。

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

これら両方を1行で定義するマクロを作成したいと思います。それは私のヘッダーのサイズを少なくとも10分の1に減らすでしょう!これが私の最も近い試みです(しかし十分にはほど遠いです):

#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

C ++でプリプロセッサを悪用しようとすることは、通常、悪い考えです。

ニーズに合わない理由はありboost::signalますか?

ボーナスとして、メンバー関数をオブジェクトインスタンスにバインドし、グローバルを取り除くために使用できますstd::function(または、C ++ 03ランドで立ち往生している場合)。boost::function

于 2012-05-08T21:37:57.287 に答える
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 に答える