V8 用の C++ クラスラッパユーティリティを書いているところ
C++ オブジェクトを Javascript オブジェクトと関連付けるためのノウハウがある程度たまってきたので、Javascript 向けバインディングを作るためのユーティリティを書いてみています。
ATL のような形で継承したクラスを作り、必要なメソッドを実装すればクラスができた〜みたいな形が一番「楽」だとは思うのですが、そこまではまだいくつも課題が残っています。
まずひとつは、ライブラリとしてどのようにコードを構造化するかでまだ悩んでいたり。
基本的に、だいたいどんなクラスでも同じようなテンプレートとなるコードにユーザが指定したコード(引数の変換等々)を挿入していく形で書いていくことになります。こういった役割はクラスの継承と virtual メンバ(仮想関数)に任せるのがよい(と思う)のですが、ここには大きな問題が。
なぜかというと、V8 からコールバックとして呼べる関数は cdecl でなければならないので、コールバックのエントリ自体はクラスで括ろうとするならば static メンバでなければなりません。static メンバは派生クラスでオーバーライドするという恩恵に与れないので、基底クラスのコードから派生クラスのメンバを指定することが難しいというわけです。
thiscall の this 部分をバインドするコードを以前書いたことがありますが、結局機械語を生成して closure を書かなければならず、ABI はおろかコンパイラのバージョン間ですら portable ではなくなってしまうのが困りもの。
とりあえず、あるクラスのコールバックコードをまとめたクラスを singleton として作ることで解決はできそう…なのですが、別 namespace にクラスを隔離しようとすると出る error C2888 に悩まされ続けています。
たとえば、こんな感じのコードなのですが、
// ラッパクラスの基底 template<class Object, class Wrapper> class WrapperBase { protected: static inline Object* Unwrap(v8::Handle<v8::Value> value) { ... } virtual const char* GetClassName() const = 0; virtual v8::Handle<v8::Value> New_(const v8::Arguments& args) { ... } // ...などなど、共通ルーチン... private: static Wrapper* instance_; protected: static Wrapper* GetInstance() { return instance_; } static v8::Handle<v8::Value> New(const v8::Arguments& args) { return GetInstance()->New_(args); } // ...static なエントリポイント... }; // で、実際にラッパクラスを作るところ namespace something { class SomethingWrapper : public WrapperBase<Something, SomethingWrapper> { // ... }; SomethingWrapper* WrapperBase<Something, SomethingWrapper>::instance_ = new SomethingWrapper(); // error: C2888 } // namespace something
最後の static メンバの初期化文でエラーになります。エラーメッセージ自体は別 namespace にあるメンバを定義できないという内容で、something namespace を抜けたところで定義すれば一応解決はできますが…なんかそういう ad hoc なことをするのもなあ。
あと、namespace を抜けてから書くと上のコードがさらにこーゆー感じで面倒になってしまって読みづらい。。。
something::SomethingWrapper* WrapperBase<something::Something, something::SomethingWrapper>::instance_ = new something::SomethingWrapper(); // ok
じゃあクラスじゃなくて、インスタンスを作る必要のない namespace でやればええやんという話もなきにしもですが。。。
ただそうすると、ベースとなるコードからユーザのコードを呼ばせるのがちと大変かなと。
うまい方法ないかなあ。