2017-01-26 4 views
1

クラスメンバ関数を呼び出す標準ライブラリを使用しない以下の例を書きました。これは期待通りに機能しますが、より一般的なものにしたいと思います。これは、8ビットマイクロコントローラを備えた組み込みシステム向けです。私は、この種のアーキテクチャにC++を使用するかどうかの議論を誘発したくありません。stlと動的メモリ割り当てを持たないメンバ関数クラス

コードは次のように動作します。クラスメンバ関数または関数にvoidポインタを使用することはできません。単一の関数に対してvoidポインターを使用することは可能ですが、これは明確な動作ではありません。

この場合、クラスメンバーを呼び出すために静的関数を使用します。メソッド呼び出し側関数は、静的テンプレート関数であり、オブジェクト型とメンバ関数ポインタをテンプレート引数として受け取ります。

bind関数は、オブジェクトポインタをvoidポインタとして格納し、クラス内のcallingFunctionを特定の静的メソッドに設定します。呼び出しが()演算子で行われるとき、callFunctionポインターは特定のオブジェクトとすべてのパラメーターで呼び出されます。

これはすべて期待どおりに動作し、バリデーショナルテンプレートのためにC++ 11を有効にしてコンパイルできます。私の意図は、APIをより快適にすることです。 f.bind(& t)を使用すると、少し時間がかかるようですが、これを行うにはもっと良い方法はわかりません。何か案は?

もう1つのポイントは、クラスの一部ではない関数を格納することです。

#include <iostream> 

class testclass { 
public: 
    virtual char test(void){ 
     return '.'; 
    } 
}; 

class testclass2 : public testclass{ 
public: 
    char test(void){ 
     return '@'; 
    } 
}; 

template<typename signature> 
class Function; 

template<typename TReturn, typename ...TParam> 
class Function<TReturn(TParam...)> { 
public: 
    template<typename TObject, TReturn (TObject::*TMethod)(TParam...)> 
    void bind(TObject *obj){ 
     this->obj = obj; 
     this->callingFunction = &methodCaller<TObject, TMethod>; 
    } 

    TReturn operator()(TParam... params){ 
     return callingFunction(this->obj, params...); 
    } 
private: 
    void *obj; 
    TReturn (*callingFunction)(void *obj, TParam...); 

    template<typename TObject, TReturn (TObject::*TMethod)(TParam...)> 
    static TReturn methodCaller(void *obj, TParam... params) { 
     TObject *c = static_cast<TObject*>(obj); 
     return (c->*TMethod)(params...); 
    } 
}; 

int main(){ 
    testclass t; 

    Function<char(void)> f; 
    f.bind<testclass, &testclass::test>(&t); 
    std::cout << f(); 

    testclass2 t1 = testclass2(); 
    f.bind<testclass, &testclass::test>(&t1); 
    std::cout << f(); 
} 
+0

どのインタフェースを使用しますか? – Jarod42

+1

より良いインターフェースはf.bind(&t、&testclass :: test)となるでしょう – Gustavo

答えて

0

以下は、あなたの期待インタフェース

template<typename signature> class Function; 

template<typename TReturn, typename ...TParam> 
class Function<TReturn(TParam...)> { 
private: 
    template <typename Obj> 
    struct Helper 
    { 
     Obj* obj; 
     TReturn (Obj::*m)(TParam...); 

     Helper(Obj* obj, TReturn (Obj::*m)(TParam...)) : obj(obj), m(m) {} 

     template <typename ... Args> 
     TReturn call(Args&&... args) { return (obj->*m)(std::forward<Args>(args)...); } 
    }; 

public: 
    template<typename TObject> 
    void bind(TObject *obj, TReturn (TObject::*m)(TParam...)){ 
     this->obj = std::make_shared<Helper<TObject>>(obj, m); 
     this->callingFunction = &methodCaller<TObject>; 
    } 

    TReturn operator()(TParam&&... params){ 
     return callingFunction(this->obj.get(), std::forward<TParam>(params)...); 
    } 
private: 
    std::shared_ptr<void> obj; 
    TReturn (*callingFunction)(void* obj, TParam...); 

    template<typename TObject> 
    static TReturn methodCaller(void *obj, TParam... params) { 
     auto* c = static_cast<Helper<TObject>*>(obj); 
     return c->call(std::forward<TParam>(params)...); 
    } 
}; 

Demo

することができます私はあなたがあなた自身のスマートポインタで標準ライブラリを取り除きたいあなたにstd::shared_ptrを交換しましょう。

+0

動的なものはありません。メモリの割り当てとstd ::を全く使用する方法はありません。 – Gustavo

+0

出力をテストするためにstd :: coutを使用しましたが、最終的なコードは8ビットプロセッサで実行されます – Gustavo

関連する問題