可以使用模板多态性来代替OO多态性吗? [英] Can template polymorphism be used in place of OO polymorphism?

查看:145
本文介绍了可以使用模板多态性来代替OO多态性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让我的头部应用模板编程(和在未来的一点,模板元编程)到现实世界的场景。我发现的一个问题是,C ++模板和多态性并不总是以我想要的方式一起播放。

I am trying to get my head around applying template programming (and at some future point, template metaprogramming) to real-world scenarios. One problem I am finding is that C++ Templates and Polymorphism don't always play together the way I want.

我的问题是如果我试图应用模板编程是不正确的(我应该使用纯旧的OOP)或如果我仍然困在OOP的心态。

My question is if the way I'm trying to apply template programming is improper (and I should use plain old OOP) or if I'm still stuck in the OOP mindset.

在这种特殊情况下,我试图解决问题使用策略模式。

In this particular case, I am trying to solve a problem using the strategy-pattern. I keep running into the problem where I end up wanting something to behave polymorphically which templates don't seem to support.

使用组合的OOP代码:

OOP Code using composition:

class Interpolator {
   public:
     Interpolator(ICacheStrategy* const c, IDataSource* const d);
     Value GetValue(const double);
}

void main(...) {
    Interpolator* i;
    if(param==1)
       i = new Interpolator(new InMemoryStrategy(...), new TextFileDataSource(...));
    else if(param==2)
       i = new Interpolator(new InMemoryStrategy(...), new OdbcDataSource(...));
    else if(param==3)
       i = new Interpolator(new NoCachingStrategy(...), new RestDataSource(...));

    while(run) {
       double input = WaitForRequest();
       SendRequest( i->GetValue(input));
    }
}

潜在模板版本:

class Interpolator<class TCacheStrategy, class TDataSource> {
   public:
     Interpolator();
     Value GetValue(const double);               //may not be the best way but
     void ConfigCache(const& ConfigObject);      //just to illustrate Cache/DS         
     void ConfigDataSource(const& ConfigObject); //need to configured

}

//Possible way of doing main?
void main(...) {
    if(param==1)
       DoIt(Interpolator<InMemoryStrategy,TextFileDataSource>(),c,d);
    else if(param==2)
       DoIt(Interpolator<InMemoryStrategy,OdbcDataSource>(),c,d)
    else if(param==3)
       DoIt(Interpolator<NoCachingStrategy,RestDataSource>(),c,d)

}

template<class T>
void DoIt(const T&  t, ConfigObject c, ConfigObject d) {
   t.ConfigCache(c);
   t.ConfigDataSource(c);
   while(run) {
      double input = WaitForRequest();
      SendRequest( t.GetValue(input));
   }
}

当我尝试将OOP实现转换为模板基于实现,Interpolator代码可以翻译没有很多痛苦。基本上,用模板类型参数替换interfaces,并添加一个机制来传递Strategy / DataSource或配置参数的实例。

When I try to convert the OOP implementation to a template-based implementation, the Interpolator code can be translated without a lot of pain. Basically, replace the "interfaces" with Template type parameters, and add a mechanism to either pass in an instance of Strategy/DataSource or configuration parameters.

但是当我下来到主,它不清楚我应该如何写,以利用模板元模板样式的程序设计风格。我经常想使用多态性,但它似乎不能很好地与模板(有时,感觉像我需要Java的类型擦除泛型...唉)。

But when I get down to the "main", it's not clear to me how that should be written to take advantage of templates in the style of template meta programming. I often want to use polymorphism, but it doesn't seem to play well with templates (at times, it feels like I need Java's type-erasure generics... ugh).

当我经常发现我想要做的是像 TemplateType<?,?> x = new TemplateType< X,Y>()其中x不关心X,Y是什么。

When I often find I want to do is have something like TemplateType<?,?> x = new TemplateType<X,Y>() where x doesn't care what X,Y is.

通常是我在使用模板时遇到的问题。

In fact, this is often my problem when using templates.


  1. 我需要再申请一个级别的
    模板?

  2. 我尝试使用闪亮的新电源模板扳手到
    将一个OOP钉安装到PCI插槽中?

  3. 或者我只是想到这一切
    在模板
    编程时出错了?

一些人已经指出这不是实际的模板元编程,所以我已经重新编写了这个问题。

A few folks have pointed out this is not actually template metaprogramming so I've reworded the question slightly. Perhaps that's part of the problem--I have yet grok what TMP really is.

推荐答案

模板提供静态多态性:你指定一个模板参数在编译时实现策略。它们不提供动态多态性,您可以在运行时为实现该策略的虚拟成员函数提供一个对象。

Templates provide static polymorphism: you specify a template parameter at compile time implementing the strategy. They don't provide dynamic polymorphism, where you supply an object at runtime with virtual member functions that implement the strategy.

您的示例模板代码将创建三个不同的类其中包含所有Interpolator代码,使用不同的模板参数和可能的内联代码编译。这可能不是你想要的从代码大小的POV,虽然没有什么明确错误。假设你正在进行优化以避免函数调用开销,那么它可能是对动态多态性的改进。更有可能是超杀。如果你想动态使用策略模式,那么你不需要模板,只需在相关的地方进行虚拟调用。

Your example template code will create three different classes, each of which contains all the Interpolator code, compiled using different template parameters and possibly inlining code from them. That probably isn't what you want from the POV of code size, although there's nothing categorically wrong with it. Supposing that you were optimising to avoid function call overhead, then it might be an improvement on dynamic polymorphism. More likely it's overkill. If you want to use the strategy pattern dynamically, then you don't need templates, just make virtual calls where relevant.

你不能有一个类型 MyTemplate<?> (除非在实例化之前出现在另一个模板中)。 MyTemplate< X> MyTemplate< Y> 是完全不相关的类(即使X和Y是相关的)也许只是这样碰巧有类似的功能,如果他们从同一个模板(他们不需要 - 一个可能是一个专业化)实例化。即使它们是,如果模板参数涉及任何成员函数的签名,那么这些函数不一样,它们只是具有相同的名称。所以从动态多态性的POV,同一个模板的实例在任何两个类相同的位置 - 他们只能玩,如果你给他们一个公共的基类与一些虚拟成员函数。

You can't have a variable of type MyTemplate<?> (except appearing in another template before it's instantiated). MyTemplate<X> and MyTemplate<Y> are completely unrelated classes (even if X and Y are related), which perhaps just so happen to have similar functions if they're instantiated from the same template (which they needn't be - one might be a specialisation). Even if they are, if the template parameter is involved in the signatures of any of the member functions, then those functions aren't the same, they just have the same names. So from the POV of dynamic polymorphism, instances of the same template are in the same position as any two classes - they can only play if you give them a common base class with some virtual member functions.

所以,你可以定义一个公共基类:

So, you could define a common base class:

class InterpolatorInterface {
public:
    virtual Value GetValue(const double) = 0;
    virtual void ConfigCache(const& ConfigObject) = 0;
    virtual void ConfigDataSource(const& ConfigObject) = 0;
    virtual ~InterpolatorInterface() {}
};

然后:

template <typename TCacheStrategy, typename TDataSource>
class Interpolator: public InterpolatorInterface {
    ...
};

现在你正在使用模板根据编译时已知的内容创建不同种类的Interpolator所以从插值器到策略的调用是非虚拟的),并且你使用动态多态性来处理它们,即使你不知道,直到运行时你想要哪个(因此从客户端到插补器的调用是虚拟的)。你只需要记住,这两个是完全独立的技术,并且决定在哪里使用它们是非常不相关的。

Now you're using templates to create your different kinds of Interpolator according to what's known at compile time (so calls from the interpolator to the strategies are non-virtual), and you're using dynamic polymorphism to treat them the same even though you don't know until runtime which one you want (so calls from the client to the interpolator are virtual). You just have to remember that the two are pretty much completely independent techniques, and the decisions where to use each are pretty much unrelated.

Btw,这不是模板元 - 编程,它只是使用模板。

Btw, this isn't template meta-programming, it's just using templates.

编辑。至于什么是TMP,这里是规范的介绍性例子:

Edit. As for what TMP is, here's the canonical introductory example:

#include <iostream>

template<int N>
struct Factorial {
    static const int value = N*Factorial<N-1>::value;
};

template<>
struct Factorial<0> {
    static const int value = 1;
};

int main() {
    std::cout << "12! = " << Factorial<12>::value << "\n";
}

观察12!已经由编译器计算,并且是编译时常数。这是令人兴奋的,因为事实证明,C ++模板系统是一个图灵完备的编程语言,C预处理器不是。根据资源限制,您可以在编译时进行任意计算,避免在编译时知道输入的情况下的运行时开销。模板可以像功能语言一样操纵它们的模板参数,模板参数可以是整数或类型。或函数,虽然那些不能在编译时调用。或其他模板,但不能作为结构的静态成员返回。

Observe that 12! has been calculated by the compiler, and is a compile-time constant. This is exciting because it turns out that the C++ template system is a Turing-complete programming language, which the C preprocessor is not. Subject to resource limits, you can do arbitrary computations at compile time, avoiding runtime overhead in situations where you know the inputs at compile time. Templates can manipulate their template parameters like a functional language, and template parameters can be integers or types. Or functions, although those can't be "called" at compile time. Or other templates, although those can't be "returned" as static members of a struct.

这篇关于可以使用模板多态性来代替OO多态性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆