7

我才意识到提出问题是多么困难……希望我能举出足够精确的例子来证明我的问题,而且足够简短,不会把所有事情都搞砸……至少有编辑的可能。

所以这就是我目前的情况。当然,我在逻辑/结构(以及无论如何命名)方面对其进行了一些修改,试图专注于我的问题的本质:

// 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 中的继承搞乱。

另一方面,提取器可能需要复杂的代码和多个成员(例如将某些输入映射到某些值的巨大映射)。所以使用模板不会有性能提升。特别是仅使用头文件的提取器,甚至可能是应该内联的函子,都是不可能的。在过去,这对我来说是一个强有力的指针,模板只会增加代码复杂性(必须处理实例化,使客户端代码的生活更加困难等),我应该尽量避免它。

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

4

4 回答 4

2

最好选择第一个选项。它更清洁且可维护。

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

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

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

于 2011-07-06T09:19:08.883 回答
1

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

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

于 2011-07-06T08:49:47.800 回答
1

您还有第三种选择,提供一个构造函数,MyType该构造函数知道如何从std::string. 或者更好的是一对迭代器,所以如果你需要MyType从字符串构造一个 s 序列,你可以使用范围。

于 2011-07-06T08:50:33.647 回答
0

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

这是我在不同方法中看到的权衡取舍。

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

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

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

于 2011-07-06T14:51:41.917 回答