我目前有一个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等,并以面向数据的方式计算它们,但不幸的是我不能这样做(由于算法问题)
答案 0 :(得分:2)
我希望编译器能够内联这一点,很难。
这不会发生。
您正在使用运行时多态性。根据定义,编译器无法知道在调用时将调用哪个函数。无论是手动执行还是让编译器执行此操作,您都要为虚拟调度付费。
您将获得的绝对大多数内联是对成员函数的调用。它仍然必须基于内存访问(获取“类型”)进行条件分支以进入“内联”部分。您添加的每个新“状态”都会将另一个条件添加到该分支。充其量,这将成为一个状态表...这与虚函数指针没什么区别:它从内存地址获取,并使用它来分支到特定的代码段。
就像vtable指针一样,只有你浪费时间实现编译器可以为你做的事情。
我强烈建议您 profile ,而不是简单地假设您的手写方法可以击败编译器。
如果您决定放弃语言级别的多态性,那么您应该使用boost.variant
和相应的访问者。你的代码看起来像这样:
typedef boost::variant<A, B> Wrapper;
struct FooVisitor : public boost::static_visitor<>
{
template <typename T> void operator()(T &t) {t.foo()};
};
您必须为要呼叫的每个功能设置FooVisitor
。要调用它,请执行以下操作:
Wrapper a = existingA;
boost::apply_visitor(FooVisitor(), a);
显然,你可以将它包装在一个简单的函数中:
void CallFoo(Wrapper &a) {boost::apply_visitor(FooVisitor(), a);}
事实上,你可以制作一个完整的模板系列:
template<typename Visitor>
void Call(Wrapper &a) {boost::apply_visitor(Visitor(), a);}
请注意,不允许参数传递(您必须将参数存储在访问者本身中),但它们可以具有返回值(您必须将返回类型放在访问者的boost::static_visitor<Typename_Here>
声明中)。
另请注意,boost::variant
个对象具有值语义,因此副本将复制内部对象。您也可以使用boost::get()
语法来获取实际类型,但除非确实需要它,否则我不会建议它。只需使用访客。
答案 1 :(得分:1)
你有两个选择。您可以在编译时进行功能选择,也可以在运行时进行。如果是运行时间,那么你不会比现有的虚拟机制做得更好。如果是编译时,您将需要使用不同的代码,但是您可以使用模板自动完成该过程。
template<typename T>
struct Wrapper
{
void foo()
{
t.foo();
}
T t;
};
当然这个例子是高度抽象的,我看不出直接使用Wrapper
类和模板类型之间的任何区别。你必须更多地充实你的榜样以获得更好的答案。