How to achieve dynamic polymorphism (run-time call dispatch) on unrelated types?

后端 未结 4 440
说谎
说谎 2021-02-01 23:50

GOAL:

I would like to achieve type-safe dynamic polymorphism (i.e. run-time dispatch of a function call) on unrelated types

4条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2021-02-02 00:22

    Some time has passed, C++14 is being finalized, and compilers are adding support for new features, like generic lambdas.

    Generic lambdas, together with the machinery shown below, allow achieving the desired (dynamic) polymorphism with unrelated classes:

    #include 
    
    template
    class delegating_visitor : public boost::static_visitor
    {
    public:
        delegating_visitor(F&& f) : _f(std::forward(f)) { }
        template
        R operator () (T x) { return _f(x); }
    private:
        F _f;
    };
    
    template
    auto make_visitor(F&& f)
    {
        using visitor_type = delegating_visitor>;
        return visitor_type(std::forward(f));
    }
    
    template
    auto vcall(V&& vt, F&& f)
    {
        auto v = make_visitor(std::forward(f));
        return vt.apply_visitor(v);
    }
    
    #define call_on_variant(val, fxn_expr) \
        vcall(val, [] (auto x) { return x-> fxn_expr; });
    

    Let's put this into practice. Supposing to have the following two unrelated classes:

    #include 
    #include 
    
    struct A
    {
        int foo(int i, double d, std::string s) const
        { 
            std::cout << "A::foo(" << i << ", " << d << ", " << s << ")"; 
            return 1; 
        }
    };
    
    struct B
    {
        int foo(int i, double d, std::string s) const
        { 
            std::cout << "B::foo(" << i << ", " << d << ", " << s << ")"; 
            return 2;
        }
    };
    

    It is possible to invoke foo() polymorphically this way:

    int main()
    {
        A a;
        B b;
    
        boost::variant v = &a;
        auto res1 = call_on_variant(v, foo(42, 3.14, "Hello"));
        std::cout << std::endl<< res1 << std::endl;
    
        v = &b;
        auto res2 = call_on_variant(v, foo(1337, 6.28, "World"));
        std::cout << std::endl<< res2 << std::endl;
    }
    

    And the output is, as expected:

    A::foo(42, 3.14, Hello)
    1
    B::foo(1337, 6.28, World)
    2
    

    The program has been tested on VC12 with November 2013's CTP. Unfortunately, I do not know of any online compiler that supports generic lambdas, so I cannot post a live example.

提交回复
热议问题