【问题标题】:C++: How is this technique of compile-time polymorphism called and what are the pros and cons?C++:这种编译时多态性技术是如何被称为的,优缺点是什么?
【发布时间】:2017-10-05 12:37:57
【问题描述】:

在工作中,我遇到过基本上是这样的代码:

#include <iostream>

using namespace std;

enum e_Specialization {
    Specialization_A,
    Specialization_B
};

template<e_Specialization>
class TemplatedBase {
public:
    string foo() { return "TemplatedBase::foo"; }
};

template<>
string TemplatedBase<Specialization_A>::foo() { return "TemplatedBase<Specialization_A>:foo"; }

int main() {
    TemplatedBase<Specialization_A> o;
    cout << o.foo() << endl;
    return 0;
}

哪个输出

TemplatedBase<Specialization_A>:foo

我无法在任何地方找到有关此技术的任何讨论。

代码的创建者主要从事物的优化方面争辩说,不会发生虚拟调度。在我们的例子中,这种优化不是必需的,但我知道它有什么用处。

我的问题是:

  1. 这种技术在任何地方都有记录吗?它有名字吗?

  2. 与继承的特化相比,这有什么优势吗?

    3.这与 CRTP 有何关系?在我看来,CRTP 的所有优点和缺点似乎都是一样的。

【问题讨论】:

  • 我不明白这怎么能达到和CRTP一样的效果。
  • 优势,相比什么?很难说什么是优势,什么不是。你建议什么替代方案?此外,您的唯一实现非常简单。 foo 有一个默认实现真的很重要吗?有多少功能?等等。
  • @cpplearner:这两种技术都实现了静态多态性,即无需虚拟化
  • "消除对虚拟的需要" CRTP 并没有消除对虚拟调度的需要。它使您可以方便地表达首先不需要虚拟调度的设计。
  • @schieferstapel 重复多次的误解不会成为现实。 CRTP 只允许在最初不需要它的情况下绕过虚拟调度。具体来说,当对象的类型在编译时已知时。

标签: c++ templates virtual-functions


【解决方案1】:

至于该技术是否已记录在案(如果您使用 C++11 或更高版本执行此操作,请使用枚举类),这是一种相当常见的技术,在枚举或布尔值上进行模板化,然后执行您的专业。

一个明显的区别是,使用这种技术,您显然不能在不修改主要代码的情况下添加更多特化。一个枚举(或枚举类)只有这么多值。这可能是好事也可能是坏事,这取决于您是否希望对其进行集中跟踪。但这可以很容易地通过对一个类进行模板化并对其进行封装来改变,这是第三种选择,它既不是这种技术,也不涉及公共继承。

恕我直言,这种技术的最大优势在于您可以选择内联实现事物。例如:

template<e_Specialization e>
class TemplatedBase {
public:
    void bar() {
        // code
        if (e == Specialization_A) {
        ...
        }
        // code
    }
};

我经常看到从一开始就处于性能关键路径的类。可能有一个布尔变量来控制是否发生侵入式性能分析​​。因为这些分支在编译时是已知的,所以它们被简单地优化了。这是一个很好的方法,因为您仍然可以在同一构建中使用该类的两个版本(例如,在两者上运行单元测试)。

与继承相比的另一个区别是派生类可以在需要时轻松添加状态。就目前而言,这种技术需要专门化整个类来添加状态。同样,这可能是好是坏;如果您不需要打破这些约束,则更受约束的设计是好的。您可以轻松更改设计以添加额外的状态:

template <e_Specialization e>
struct ExtraState {};

template <e_Specialization e>
class TemplatedBase : private ExtraState<e> {
...

第三个小例子是您没有公开任何继承关系。这通常很小,但请记住,您可以获得切片甚至隐式引用/指针转换之类的东西。对于这种技术来说,这是一个非常严格的胜利。

总之,我想说:

  • 如果您利用实现一次的能力并内联编写差异而没有性能损失,那将是一场胜利
  • 如果您想在设计中明确说明实现的数量有限,这是一个胜利。

如果两者都不正确,那么与仅使用继承相比,该设计有点不正统且复杂一点,尽管它实际上并没有任何明显的技术劣势。因此,如果您周围有很多初级开发人员,那么这段代码可能会更难阅读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 2011-10-23
    • 2017-01-15
    • 2014-07-24
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    相关资源
    最近更新 更多