使用模板的 C++ 静态分派(dispatch)

标签 c++ templates

假设我有一些如下所示的 C++ 代码:

class Base {
    virtual void dummy() = 0;
    // this is to generate a vtable, but note there is no virtual f()
};

class A : public Base {
public:
    void f() { /* ... */ };
    void dummy() {};
}

class B : public Base {
public:
    void f() { /* different implementation from A */ };
    void dummy() {};
}

template<class T1, class T2, class T3>
void doStuff(T1 &x, T2 &y, T3 &z) {
    for (i=1; i<100000; ++i) {
        x.f();
        y.f();
        z.f();
    }
}

此处的目的是避免在内循环期间调用 f() 的虚函数,以便允许编译器优化。 (这显然是我实际代码的简化版本。有关我的用例的详细信息,请参阅 more specific question)。

如果 doStuff 的参数类型在运行时是已知的,则此方法工作正常,但如果不是,则失败:

int main() {
    Base *x = new A();
    Base *y = new B();
    Base *z = new A();

    doStuff(*x, *y, *z); 
    // oops - this instantiates to doStuff(Base &, Base &, Base &)
    // and there's no Base::f().
}

为了解决这个问题(如 this answer 所建议的),我似乎必须明确地构造一个静态调度函数:

void doStuff(Base &x, Base &y, Base &z) {
    A *a_x = dynamic_cast<A*>(&x);
    B *b_x = dynamic_cast<B*>(&x);
    A *a_y = dynamic_cast<A*>(&y);
    B *b_y = dynamic_cast<B*>(&y);
    A *a_z = dynamic_cast<A*>(&z);
    B *b_z = dynamic_cast<B*>(&z);
    if (a_x && a_y && a_z) {
        doStuff(*a_x, &a_y, &a_z);
    } else if (a_x && a_y && b_z) {
        doStuff(*a_x, &a_y, &b_z);
    } 
    // ... and so on for all eight combinations of A and B.
}

但这是一些非常烦人的重复代码,如果我有几个函数与 doStuff 类似,它很快就会变得难以管理,尤其是当其中任何一个有四个或更多参数时。

所以我的问题是,有什么办法可以避免这种重复的代码吗?看起来更巧妙地使用模板应该能够消除它,但我不太明白如何去做。

最佳答案

你的问题的标题:“静态分派(dispatch)” - 不幸的是你的问题需要在运行时找出类型......你想从一些基类指针中识别实际类型。这仅在运行时有效。

使用 dynamic_cast 是一种 hack,使用 dynamic_cast 通常意味着糟糕的 OO 设计。顺便说一句,我敢打赌,使用 dynamic_cast(dynamic_cast 可能会很慢!)然后静态函数调用比简单地制作 f() virtual 并将其放入您的基类并以这种方式调用它。

当然,你的情况有点特殊,你想对所有 8 个情况执行其他操作,但在我看来,这是一项你无法使用 C++ 中的简短代码优雅地解决的肮脏工作。可以打造一种不易出错/易于扩展或性能更好的解决方案,但它们都不会简短和/或优雅。您当前的 doStuff() 实现是一个不太容易出错的“防弹”解决方案,我刚刚想到另一个丑陋的解决方案,即使对于许多派生类和类组合也具有良好的性能(带有自己的 gettype + switch 的自己的类型枚举)但这太丑陋了。

总结一下:这个问题在 C++ 中没有很好的解决方案。当涉及到无法在 C++ 中优雅地解决的问题时,您必须重新考虑您的设计,或者您不得不忍受丑陋的代码:例如,在序列化的情况下,您经常会发现这样丑陋的代码......

关于使用模板的 C++ 静态分派(dispatch),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22139344/

相关文章:

c++ - 如何将 float 舍入到 C++ 中的下一个 0.5 增量?

常量的 C++ 最佳实践

c++ - C++中的默认构造函数如何初始化变量

templates - 是否有任何可以在客户端和服务器端使用的 ASP.NET 模板技术?

c++ - 将整型变量地址分配给字符指针

c++ - Nicolai Josuttis 在他的书中说,开放成员函数不会清除状态标志。这不是我在 VS2010 中发现的。这是微软的问题吗?

c++ - 如何从 Win32 C++ 应用程序输出到父控制台窗口?

c++ - 如何制作一个 C++ 模板类,根据模板值的类更改其成员和访问器?

c++ - 为什么 void 在 C++ 中不采用 void 值?

c++ - 在 C++ 中使用 STXXL 模板的递归模板函数出错