Design pattern for exception-safe trampolines

后端 未结 2 1207
悲&欢浪女
悲&欢浪女 2021-01-15 09:38

This question follows from here. However, the previous question was worded so badly (wrongly in fact) that it was suggested I ask again from scratch.

I have a table

2条回答
  •  再見小時候
    2021-01-15 10:03

    I got it working thanks to Piotr's answer to my previous question, from which I have lifted the core machinery (so please upvote his answer).

    Coliru here

    #include 
    #include 
    
    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(s);
    }
    
    template 
    struct trap;
    
    template 
    struct trap
    {    
        static R 
        call(void* s, Args... args)
        {
            std::cout << "trap:" << typeid(t).name() << std::endl;
            try
            {
                return (get_base(s)->*t)(std::forward(args)...);
            }
            catch (...)
            {
                std::cout << "CAUGHT" << std::endl;
                return std::is_integral::value ? static_cast(-42) : static_cast(-3.14); 
            }
        }
    };
    
    
    #define TRAP(f)  & trap::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(&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!)
    }
    

提交回复
热议问题