2

この質問はここから続きます。しかし、前の質問の言い回しが非常に悪かったため (実際には間違っていました)、最初からもう一度質問するよう提案されました。

C 関数ポインターのテーブルがあります。

一部の C コード (lib-X と呼びましょう) には、基本的な構成要素 (X オブジェクトと呼びましょう) があります。各 X オブジェクトは、このテーブルの関数を呼び出すことができます。

これらのテーブル関数は、通常、異なるシグネチャを持ちます (ここの typedef を参照)。ただし、複数の関数が同じシグネチャを共有することは可能です。表には、これらの関数が約 100 あります。

C++ では、各 X オブジェクトに関連付けられた Final:Base クラスがあります。

そして、これらの呼び出しを X オブジェクトの対応する C++ Final インスタンスに転送したいのですが、C++ コンシューマーがバグのある Final を提供する可能性があるため、これを try/catch 内に囲みたいと思います。

したがって、テーブルの各エントリに対して仮想関数を持つ C++ 基本クラスがあります。

次に、基本クラスから派生した C++ Final クラス (多くの場合、Final1 Final2 Final3 など) があります。

だから今、私はハンドラーを書く必要があります

  1. 最初の「self」パラメーターを取得します (これは常に、関数を呼び出した X オブジェクトへのポインターになります)

  2. 関連する C++ 基本クラス インスタンスを取得します。

  3. try catch ブロック内で、対応する仮想関数を呼び出し、残りのすべてのパラメーターを転送します。

  4. ...実際に Final でオーバーライドを呼び出します。

これは、インセプションのプロットを理解しようとするようなものです。lib-X は実際には Python ランタイムですが、私は物事を一般的なものにしようとしています。

問題は、これらの関数が数十あることです。これにより、非常に面倒で保守不可能な C++ コードが作成されます。それぞれのトランポリン関数を手動で作成する必要がある場合は、次のようになります。

extern "C" PyObject *call_handler( PyObject *self, PyObject *args, PyObject *kw )
{
    try
    {
        PythonExtensionBase *p = getPythonExtensionBase( self );
        if( kw != NULL )
            return new_reference_to( p->call( Object(args), :Object(kw) ) );
        else
            return new_reference_to( p->call( Object(args), Object() ) );
    }
    catch( Py::Exception & )
    {
        return NULL; // indicate error
    }
}

(ソースはこちら

私は、この例外的に安全なトランポリンを可能にするコンパクトなデザインを考え出そうとしています.

現在の進捗状況は [削除済み、下記の回答を参照]

4

2 に答える 2

3

以前の質問に対する Piotr の回答のおかげで、私はそれを機能させました。そこからコア機構を持ち上げました (彼の回答に賛成票を投じてください)。

コリルはこちら

#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual int   func_1( int a )        { std::cout << "Base::func_1" << std::endl; return a; }
    virtual float func_2( int a, int b ) { std::cout << "Base::func_2" << std::endl; return a+b; }
    virtual float func_3( char a )       { std::cout << "Base::func_3" << std::endl; return (float)a; }
};

class Final : public Base {
public:
    int   func_1( int a )           override { std::cout << "Final::func_1" << std::endl; return a+1000; }
  //float func_2( int a, int b )    override { std::cout << "Final::func_2" << std::endl; return a*b; }
    float func_3( char a )          override { std::cout << "Final::func_3" << std::endl; throw 666; }
};

Base* get_base(void* s) {
    return reinterpret_cast<Base*>(s);
}

template <typename T, T t>
struct trap;

template <typename R, typename... Args, R(Base::*t)(Args...)>
struct trap<R(Base::*)(Args...), t>
{    
    static R 
    call(void* s, Args... args)
    {
        std::cout << "trap:" << typeid(t).name() << std::endl;
        try
        {
            return (get_base(s)->*t)(std::forward<Args>(args)...);
        }
        catch (...)
        {
            std::cout << "CAUGHT" << std::endl;
            return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14); 
        }
    }
};


#define TRAP(f)  & trap<decltype(&f), &f>::call

class Trampoline 
{
    using F1 = auto ( void* self, int a )         -> int;
    using F2 = auto ( void* self, int a, int b )  -> float;
    using F3 = auto ( void* self, char a )        -> float;

    struct Table {
        F1* fp_1;
        F2* fp_2;
        F3* fp_3;
    };
public:
    Table* table = new Table();

    void enable_f1() { table->fp_1 = TRAP( Base::func_1 ); }
    void enable_f2() { table->fp_2 = TRAP( Base::func_2 ); }
    void enable_f3() { table->fp_3 = TRAP( Base::func_3 ); }
};

int main()
{
    Trampoline trampoline{};

    trampoline.enable_f1();
    trampoline.enable_f2(); 
    trampoline.enable_f3(); 

    Final final{};

    void* base_as_pvoid = (void*)static_cast<Base*>(&final);

    // test
    int u    = trampoline.table->fp_1( base_as_pvoid, 2 );     std::cout << u << std::endl; // expect: 1002   (enabled and Final provides override)
    float v  = trampoline.table->fp_2( base_as_pvoid, 3, 5 );  std::cout << v << std::endl; // expect: 8      (enabled but no override)
    float w  = trampoline.table->fp_3( base_as_pvoid, 'x' );   std::cout << w << std::endl; // expect: -3.14  (enabled and Final provides override, which throws!)
}
于 2015-01-08T00:10:41.353 に答える