C++模板化与继承

发布于 2024-11-18 19:26:37 字数 1849 浏览 11 评论 0原文

我只是意识到提出问题是多么困难......希望我能给出的例子既足够精确来证明我的问题,又足够短,不会把一切搞砸......至少有编辑的可能性。

这就是我目前的情况。当然,我在逻辑/结构方面(以及命名方面)稍微改变了它,试图专注于我的问题的本质:

// MyClass deals with lists (actually several data structures) of the
// type MyType which should support different types and has to be 
// efficiently dealt with. Templating seems just right here
class MyClass
{
  ...

  void doSomething<class MyType>(vector<MyType> someList);

  ...

  // At some point I have to extract elements of the type MyType.
  // The extractor obviously depends on MyType but it is not possible to
  // Create a general version that could use templates itself 
  // (unless I use a specialization for each possible MyType)

  // I am stuck between these two alternatives:

  // Possibility1:
  // Let the client pass the right extractor and template it.
  template<class Extractor, class MyType>
  void extract(const Extractor& extractor, const string& source, 
               vector<MyType>* dest)
  {
     extractor.extract(source, dest);
  }

  // Possibility2:
  // Use a member _extractor of some base type that has to be set
  // to a specialization. The ExtractorBase has a virtual method
  // template<T> void extract(const string& source, vector<T>* myType) = 0
  // with no definition that is only defined in subclasses wrt certain
  // postings.
  ExtractorBase _extractor;

  template<class MyType>
  void extract(const string& source, vector<MyType>* dest)
  {
     _extractor.extract(source, dest);
  }
}

目前我更喜欢可能性1,因为我不必在继承中搞乱适用于 MyType 的所有变体的 Extractor 以及我想在将来尝试的相关 Extractor。

另一方面,提取器可能需要复杂的代码和多个成员(类似于将某些输入映射到某些值的巨大地图)。因此使用模板不会带来性能提升。特别是仅使用头文件提取器,甚至可能应该内联的函子,都是不可能的。在过去,这一直向我强烈表明,模板只会增加代码复杂性(必须处理实例化,使客户端代码的生活变得更加困难等),并且我应该尝试完全避免它。

还是还有第三种我根本没有想到的可能性?

I just realize how hard asking questions can be... Hopefully I can give examples that are both, sufficiently precise to demonstrate my problem and short enough not to mess everything up... At least there's the possibility to edit.

So this is kind of my situation at the moment. Of course I altered it a bit in terms of logic / structure (and in terms of naming anyway) trying to focus on the essence of my question:

// MyClass deals with lists (actually several data structures) of the
// type MyType which should support different types and has to be 
// efficiently dealt with. Templating seems just right here
class MyClass
{
  ...

  void doSomething<class MyType>(vector<MyType> someList);

  ...

  // At some point I have to extract elements of the type MyType.
  // The extractor obviously depends on MyType but it is not possible to
  // Create a general version that could use templates itself 
  // (unless I use a specialization for each possible MyType)

  // I am stuck between these two alternatives:

  // Possibility1:
  // Let the client pass the right extractor and template it.
  template<class Extractor, class MyType>
  void extract(const Extractor& extractor, const string& source, 
               vector<MyType>* dest)
  {
     extractor.extract(source, dest);
  }

  // Possibility2:
  // Use a member _extractor of some base type that has to be set
  // to a specialization. The ExtractorBase has a virtual method
  // template<T> void extract(const string& source, vector<T>* myType) = 0
  // with no definition that is only defined in subclasses wrt certain
  // postings.
  ExtractorBase _extractor;

  template<class MyType>
  void extract(const string& source, vector<MyType>* dest)
  {
     _extractor.extract(source, dest);
  }
}

At the moment I would prefer possibility1, because I don't have to mess with inheritance in Extractor for all the variants of MyType and associated Extractor I want to try out in the future.

On the other hand extractors may require complex code and several members (something like huge maps that map certain inputs on certain values). So there will be no performance gain by using templates. Particularly using header file only Extractors and probably even functors that are supposed to get inlined, are kind of out of the question. In the past, this has been a strong pointer to me that templating will only increase code complexity (having to deal with instantiation, making life harder for client code, etc.) and that I should try to avoid it altogether.

Or is there a third possibility I didn't think of at all?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

笑忘罢 2024-11-25 19:26:37

最好选择第一个选项。它更干净且可维护。

因为从您的评论中,我发现您对第二个选项做出了错误的假设:

// The ExtractorBase has a virtual method
// template<T> void extract(const string& source, vector<T>* myType) = 0;

。那是不可能的; 模板函数永远不能是虚拟。因此,要实现第二个选项,您必须选择一些肮脏且难以维护的方法,这不是一个好主意。

It's better to go with the first option. It's cleaner and maintainable.

Because from your comments, I am making out that you are making a wrong assumption for the 2nd option:

// The ExtractorBase has a virtual method
// template<T> void extract(const string& source, vector<T>* myType) = 0;

NO. That's not possible; a template function can never be virtual. So to implement the 2nd option you have to opt for some dirty and hard to maintain ways, which is not a good idea.

新雨望断虹 2024-11-25 19:26:37

您还有第三个选择,为 MyType 提供一个构造函数,它知道如何从 std::string 构造自身。或者更好的是一对迭代器,因此如果您需要从字符串构造 MyType 序列,则可以使用范围。

You have a third option, provide a constructor for MyType which knows how to construct itself from a std::string. Or better yet a pair of iterators, so if you need to construct a sequence of MyTypes from the string, you can use the range.

呆萌少年 2024-11-25 19:26:37

我认为第一种可能性更灵活。

在第二种可能性中,我没有看到将不需要的封装提取器作为类成员的兴趣。 MyClass 和 Extractor 之间的耦合也更多,这不是一件好事。模板化减少了耦合(在某种程度上),所以如果你有选择的话,它是一个更好的选择。

I see first possibility as more flexible.

In the 2nd possibility I don't see the interest of unneeded encapsulating extractor as class member. You also have more coupling between MyClass and Extractor, which is not a good thing. templating reduces coupling (in some way), so if you have the choice it's a better one.

眼趣 2024-11-25 19:26:37

这听起来像是策略模式的一个例子——你的类有一个操作,其实现可能会有所不同。

以下是我在不同方法中看到的权衡。

模板解决方案将避免声明抽象接口类,并使用 vtbl 来确定要使用哪个实现。但它会迫使您在编译时锁定应用程序。

继承解决方案将强制您声明一个抽象接口类,并承受在 vtbl 中查找实现的性能损失。但它允许您在运行时选择提取实现。

由于不知道性能对于您的应用程序有多重要以及您需要多么灵活,我可能会选择继承解决方案,因为我喜欢在抽象类中定义接口并对其进行编码的清晰度。

This sounds like a case for the Strategy Pattern -- your class has an operation whose implementation may vary.

Here's the trade-offs I see in the different approaches.

The template solution will avoid having to declare an abstract interface class, and using the vtbl to figure out which implementation to use. But it will force you to lock into the application at compile-time.

The inheritance solution will force you to declare an abstract interface class, and take the performance hit of looking up the implementation in the vtbl. But it will allow you to choose the extracting implementation at run time.

Not knowing how critical performance is for your application and how flexible you need to be, I would probably choose the inheritance solution, since I like the clarity of defining the interface in an abstract class and coding to that.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文