简体   繁体   English

C ++:如何调用这种编译时多态技术?优缺点是什么?

[英]C++: How is this technique of compile-time polymorphism called and what are the pros and cons?

At work, I have come across code which basically looks like that: 在工作中,我遇到了基本上看起来像这样的代码:

#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;
}

which outputs 哪个输出

TemplatedBase<Specialization_A>:foo

I haven't been able to find any discussion on this technique anywhere. 我在任何地方都找不到有关此技术的任何讨论。

The code's creator argued mostly from the optimization side of things, that no virtual dispatch happens. 该代码的创建者主要从优化方面出发,认为不会发生虚拟调度。 In our case this optimization is not necessary, but I see how it could be useful. 在我们的情况下,此优化不是必需的,但我知道它可能是有用的。

My questions are: 我的问题是:

  1. Is this technique documented anywhere and does it have a name? 此技术在任何地方都有记载吗?它有名字吗?

  2. In comparison to specialization by inheritance, are there any advantages to this at all? 与通过继承进行专业化相比,这有什么优势吗?

    3. How does this relate to CRTP? 3.这与CRTP有什么关系? To me it seems that the same is achieved, with all pros and cons of CRTP. 在我看来,CRTP的优点和缺点都可以实现。

As far as whether the technique is documented (and if you are doing this with C++11 or later, please use an enum class), it's a fairly common technique to template on an enum or a boolean and then do your specializations. 至于是否记录了该技术(如果您使用C ++ 11或更高版本,请使用枚举类),这是在枚举或布尔值上进行模板化然后进行专门化的相当普遍的技术。

One clear difference is that with this technique, you obviously can't add more specializations without modifying the primary code. 一个明显的区别是,使用这种技术,很明显,不修改主代码就无法添加更多的专业化知识。 An enum (or enum class) only has so many values. 一个枚举(或枚举类)只有这么多的值。 That could be either a good or bad thing, depending on whether you want it to be centrally tracked. 这可能是好事,也可能是坏事,这取决于您是否希望对其进行集中跟踪。 But that could easily be changed by templating on a class and encapsulating it, a third option which isn't quite this technique nor does it involve public inheritance. 但这可以通过对类进行模板化和封装来轻松地进行更改,这是第三个选择,它既不是这项技术,也不涉及公共继承。

This technique has its biggest advantage, IMHO, in that you have the option to implement things inline. 这项技术的最大优点是恕我直言,因为您可以选择内联实现。 For example: 例如:

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

I see this a lot with classes that are known from the outset to be in a performance critical path. 从一开始就知道对性能至关重要的类中,我看到了很多。 There could be a boolean variable that controls whether or not intrusive performance profiling occurs. 可能有一个布尔变量,用于控制是否进行侵入式性能分析​​。 Because these branches are known at compile time, they are trivially optimized. 由于这些分支在编译时是已知的,因此对其进行了优化。 This is a good way to do it because you can still use both versions of the class in the same build (eg run unit tests on both). 这是一个很好的方法,因为您仍然可以在同一版本中使用该类的两个版本(例如,在两个版本上都运行单元测试)。

Another difference compared to inheritance, is that derived classes can easily add state if they need to. 与继承相比,另一个区别是,如果需要,派生类可以轻松添加状态。 This technique as it stands would require specializing the whole class to add state. 就目前的技术而言,将需要对整个类进行专门化以添加状态。 Again, this could be good or bad; 同样,这可能是好是坏。 a more constrained design is good if you don't need to break those constraints. 如果您不需要打破这些约束,那么约束性更好的设计将是一件好事。 And you can easily change the design to enable adding extra state: 而且,您可以轻松更改设计以启用添加额外状态的功能:

template <e_Specialization e>
struct ExtraState {};

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

A third, minor example, is that you aren't exposing any inheritance relationship. 第三个较小的示例是您没有公开任何继承关系。 This is mostly small, but remember that you can get things like slicing or even implicit reference/pointer conversion. 这通常很小,但是请记住,您可以进行切片甚至隐式引用/指针转换。 This is a pretty strict win for this technique. 对于这项技术,这是一个相当严格的胜利。

In sum I would say that: 总而言之,我会说:

  • It's a win if you utilize the ability to implement something once and write the differences inline with no perf penalty 如果您利用一次实施某项功能并以内嵌的方式编写差异而无性能损失的能力,那将是一个胜利
  • It's a win if you want to be explicit in your design about there being a limited number of implementations. 如果您想在设计中明确实现数量有限,那是一个胜利。

If neither of those are true then the design is a bit unorthodox and a little more complex compared to just using inheritance, although it doesn't really have any strong technical disadvantage. 如果这两个都不是正确的,那么与仅使用继承相比,该设计就有点不合常规,并且要复杂一些,尽管它实际上并没有任何强大的技术缺点。 So if you have a good number of junior devs around, this code might be harder to read. 因此,如果您周围有大量初级开发人员,则此代码可能更难阅读。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM