今、C++で書かれたアプリケーションがあり、このアプリケーションに拡張用のスクリプト言語(mrubyを想定)を実装しています。
このスクリプト言語からアプリケーションを操作したり、オブジェクトを取得する為のコールバック関数を登録するのですが、このコールバック関数の頭に
必ず入るコードがあります。
コールバック関数はstaticメンバ関数か、あるいは通常の関数でなければならない為、クラスのインスタンスがThisで渡されるという事はありませんので、
スクリプト言語管理用クラス(CmrubyManとする)のインスタンスを取得する関数(GetInstanceとする)が各コールバック関数の頭に書かれます。
この頭に書かれる部分は完全に共通な為、出来るだけ纏めたい(1行以下にしたい)訳ですが、この書き方についてです。
幾つか実装手段を考えました。
1.テンプレートクラスを使う
C++
1//テンプレートクラス 2template <class Proc> class CMRubyCallbackTemplate { 3public: 4 static mrb_value Caller(mrb_state *mrb, mrb_value self) { 5 CMrubyMan *instance ; 6 instance = CMrubyMan::GetInstance() ; 7 if(instance == NULL) { 8 // 共通エラー処理 9 return mrb_nil_value() ; 10 } 11 return Proc::DoCallback(instance, mrb, self) ; 12 } 13} 14 15//呼び出されるメソッドの定義クラス 16class CMrbMethod1Class 17{ 18public: 19 static mrb_value DoCallback(CMrubyMan *instance, mrb_state *mrb, mrb_value self) { 20 実際の処理 21 return ~ 22 } 23} ;
登録時に
C++
1mrb_define_method(mrb, UserClass, "Method1", CMrubyCallbackTemplate<CMrbMethod1Class>::Caller, MRB_ARGS_NONE()) ;
という感じで
2.昔ながらのマクロ化
C++
1#define GetInstance() CMrubyMan *instance ; \ 2 instance = CMrubyMan::GetInstance() ; \ 3 if(instance == NULL) { \ 4 return mrb_nil_value() ; \ 5 }
と定義しておき
C++
1mrb_value Method1(mrb_state *mrb, mrb_value self) { 2{ 3 GetInstance() ; 4 実際の処理~ 5 6 return ~ 7}
で登録は
C++
1mrb_define_method(mrb, UserClass, "Method1", Method1, MRB_ARGS_NONE()) ;
という感じで。
他にも恐らくstd::functionを使う方法や他にもあると思いますが、結局どう書くのが一番スマートなのか?という点についてです。
テンプレートクラスを使う方法は拡張性があると思いますが、記述が長ったらしく、しかもメソッド毎にclassを1個作るのが
とても冗長に感じます。
マクロ化の方は記述が簡単で素直な方法だと思うのですが、例えば頭だけでなくおしりにも共通処理を入れたいとなった途端に破綻します。
とりあえず現状はマクロ化でやっているのですが、皆さんならどうしますか?
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/23 04:23
2016/07/23 04:43