1

我目前有一个 C++ 接口

void foo() ...

和许多实现

void A::foo();
void B::foo();

目前 foo 定义如下

struct Wrapper
{
    void foo()
    {
        if(state == STATE_A) a.foo();
        else if(state == STATE_B) b.foo();
    }
    union {
        A a;
        B b;
    };
    State state;
}
//....
Wrapper a(STATE_A, existingA);
Wrapper b(STATE_B, existingB);
a.foo(); b.foo();

有没有更清洁的方法来做到这一点?我有多个类似 foo() 的函数和多个类似 A/B 的类。编写所有案例变得乏味/容易出错。

请注意,我不能使用虚函数(它在 N^5 循环内运行……每秒执行 1000 万次以上)。我希望编译器内联这个,很难。

我曾想过将 A、B 等一起收集并以面向数据的方式计算它们,但不幸的是我不能这样做(由于算法问题)

4

2 回答 2

2

I want the compiler to inline this, hard.

That's not going to happen.

You're using runtime polymorphism. By definition, the compiler cannot know which function will be called at call time. You are going to pay for virtual dispatch, whether you do it manually or let the compiler do it.

The absolute most inlining you will get is in the calls to the member functions. It still has to do a conditional branch based on a memory access (fetching the "type") to get to the "inline" part. And every new "state" you add will add another condition to that branch. At best, this will become a state table... which is no different from just a virtual function pointer: it fetches from a memory address, and uses that to branch to a particular piece of code.

Just like a vtable pointer, only you wasted your time implementing something the compiler could do for you.

I strongly advise you to profile this instead of simply assuming that your hand-written method can beat the compiler.


If you've decided to abandon language-level polymorphism, then you should use a boost.variant and appropriate visitors instead. Your code would look like this:

typedef boost::variant<A, B> Wrapper;

struct FooVisitor : public boost::static_visitor<>
{
  template <typename T> void operator()(T &t) {t.foo()};
};

You will have to make a FooVisitor for every function you want to call. To call it, you do this:

Wrapper a = existingA;
boost::apply_visitor(FooVisitor(), a);

Obviously, you can wrap that in a simple function:

void CallFoo(Wrapper &a) {boost::apply_visitor(FooVisitor(), a);}

Indeed, you can make a whole template family of these:

template<typename Visitor>
void Call(Wrapper &a) {boost::apply_visitor(Visitor(), a);}

Note that parameter passing is not allowed (you have to store the parameters in the visitor itself), but they can have return values (you have to put the return type in the boost::static_visitor<Typename_Here> declaration of your visitor).

Also note that boost::variant objects have value semantics, so copies will copy the internal object. You can also use the boost::get() syntax to get the actual type, but I would not suggest it unless you really need it. Just use visitors.

于 2012-05-11T02:07:18.083 回答
1

你有两个选择。您可以在编译时进行函数选择,也可以在运行时进行。如果是运行时,你不会比现有的虚拟机制做得更好。如果是编译时间,您需要为要使用的每种类型使用不同的代码,但您可以使用模板来自动化该过程。

template<typename T>
struct Wrapper
{
    void foo()
    {
        t.foo();
    }
    T t;
};

当然这个例子是高度抽象的,我看不出Wrapper直接使用类和模板类型有什么区别。您必须更加充实您的示例才能获得更好的答案。

于 2012-05-11T02:26:16.847 回答