C++中方法和对象选择的静态多态性

Ami*_*rsh 2 c++ macros templates boost-variant static-polymorphism

尝试在没有基类和虚拟调用的情况下获取编译时方法和对象选择.

情况如下:

struct A {
    void f1()const { cout << "A::f1" << endl;}
    void f2()const { cout << "A::f2" << endl;}
};

struct B {
    void f1()const { cout << "B::f1" << endl;}
    void f2()const { cout << "B::f2" << endl;}
};

class Holder {
    A* _a = nullptr;
    B* _b = nullptr;
public:
    Holder(A* a): _a(a) {}
    Holder(B* b): _b(b) {}
    void f1()const {
        if(_a)       _a->f1();
        else if(_b)  _b->f1();
    }
    void f2()const {
        if(_a)       _a->f2();
        else if(_b)  _b->f2();
    }
};

void f(const Holder& h) {
    h.f1();
}

int main() {
    B obj;
    Holder h(&obj);
    f(h);
}
Run Code Online (Sandbox Code Playgroud)

http://coliru.stacked-crooked.com/a/4b5acec6866cfd4e

假设A和B之类的类很少,但可能有很多函数,比如f1和f2.

Holder需要在它拥有的实际对象上调用函数,没有多态性,也不需要A和B的继承/共享接口.

寻找一种很好的方式来做类似的事情:

class Holder {
    A* _a = nullptr;
    B* _b = nullptr;
public:
    Holder(A* a): _a(a) {}
    Holder(B* b): _b(b) {}
    // below is pseudo code!
    void call<function>()const {
        if(_a)
            _a->function(); // function is known in compile time, sort of...
        else if(_b)
            _b->function();
    }

    void f1()const { call<f1>(); }
    void f2()const { call<f2>(); }
};
Run Code Online (Sandbox Code Playgroud)

任何的想法?

  • 宏?
  • 模板?
  • 其他技巧?

Joh*_*nck 7

您可以使用变体.这将存储从N减少到1指针加上1 int,并且不需要更改任何内容,除了Holder:

#include <boost/variant.hpp>

struct f1visitor
{
    typedef void result_type;
    template<typename T>
    void operator()(T* const t) const { t->f1(); }
};

struct f2visitor
{
    typedef void result_type;
    template<typename T>
    void operator()(T* const t) const { t->f2(); }
};

class Holder {
    boost::variant<A*, B*> _ptr;
public:
    Holder(A* a): _ptr(a) {}
    Holder(B* b): _ptr(b) {}
    void f1()const {
        boost::apply_visitor(f1visitor(), _ptr);
    }
    void f2()const {
        boost::apply_visitor(f2visitor(), _ptr);
    }
};
Run Code Online (Sandbox Code Playgroud)

使用足够新的C++,您可以使用它std::variant.

  • 使用c ++ 14,您甚至可以使用通用lambda而不是手动访问者. (4认同)