2012-05-08 6 views
1

私はC++でプリプロセッサを利用して、開発の進展を大幅に緩和しようとしています!私はかなり単純な問題を抱えています。私はC APIライブラリを使用していますが、通常のC++クラスを使用しています。このライブラリはコールバック/イベントに基づいていますが、私は関数(メソッドではありません)にしか渡すことができません。私は1行でこれらの両方を定義するマクロを作成したいC++プリプロセッサをプッシュする

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

:このため、私は、各イベントのために静的および非静的関数を宣言するの繰り返しパターンを持っています。それは私のヘッダーのサイズを少なくとも10倍減らすでしょう!私はこのDECL_EVENT(ClickLeft, Vector, 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__); 

:ここに私の最も近いの試み(しかし十分から)です。これは出力になります:

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

この問題ははっきりとわかります。 static関数はメソッドを呼び出し、引数の型と名前を指定します。型が指定されているため、コンパイラエラーが発生します。 include/plugin.h:95:2: error: expected primary-expression before ‘TOKEN’ token

どうすればこの問題を解決できますか?いくつかの解決策が必要であり、マクロの専門家が助けてくれると確信しています!

+1

Boost.Preprocessorには、ペアの2番目のコンポーネントなどを投影するために必要なツールが含まれています。いくつかの例については、[この質問](http://stackoverflow.com/q/9897074/596781)を参照してください。 –

+0

Cコールバックの宛先として静的メンバーを使用することは移植性がありません。Cからのコールバックは、** extern "C"と宣言されたC++関数を呼び出すだけでなければなりません。そうでなければ、あなたのプラットフォームで保持されているC関数と同じABIを持つC++静的メンバーメソッドに依存します。 –

+0

@ LokiAstari私は、外部の "C"関数 'LoadPlugin'(最初の答えについての私のコメントを参照してください)にコールバックを設定するために静的なC関数を使用するので、心配はありません。 –

答えて

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に展開されます。さて、次、あなたがやりたいだろうがそう、ここで、渡される各引数にこれらのマクロを適用することであるあなたは、最大8つの引数のことを行うようになる簡単なAPPLYマクロです:

/* 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) 

今HERESにどのようにあなたの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では動作しません。

+0

より良い解決策を求められませんでした。絶対に完璧に働いた!ありがとうございました! –

1

C++でプリプロセッサを乱用しようとするのは悪い考えです。

boost::signalを必要としない理由はありますか?

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

+0

私は 'boost :: signal'にはあまり経験がありませんので、詳細を記入して、私のために働くかどうかを決めることができます。私は閉じたAPI(私はそれを変更することはできません)とこのAPIに拡張機能を書き込んで作業しています。拡張機能が読み込まれると、私の拡張機能は 'LoadPlugin'(外部)呼び出しを受け取ります。この関数は関数テーブル(引数として)へのポインタを提供します。ここでは、関心のある関数を関数を指すように設定します。 'pFunctionTable-> pfnEventClickLeft =&MYCLASS :: StaticEventClickLeft'です。あなたは 'boost :: signal'がこの場合の解決策になると思いますか?私はC++に固執しています03 –

+0

残念ながら、関数ポインタと共に引数を渡すことはできません(通常は 'void *'の形式で)、状態をグローバルに公開するようになります。 –

+3

悪用を悪用するのは冗長です。また、プリプロセッサの使用方法を自動的に濫用としてラベル付けしても、誰にも役立ちません。 –

関連する問題