2010-11-02 68 views
2

我应该定义一个接口,明确告知用户他/她应该实现哪些内容才能使用该类作为模板参数,或者让该编译器在未实现该功能时警告他?强制执行模板参数类的函数?

template <Class C1, Class C2> 
SomeClass 
{ 
    ... 
} 

C1类必须实现某些方法和运算符,编译器在使用它们之前不会发出警告。我应该依靠编译器来警告或确保我这样做:

Class C1 : public SomeInterfaceEnforcedFunctions 
{ 
    // Class C1 has to implement them either way 
    // but this is explicit? am I right or being 
    // redundant ? 
} 
+0

你是多余的。如果你试图调用C1没有的方法,它不会被编译,那应该就足够了。 – 2010-11-02 18:37:48

+0

@PigBen:我不同意。如果你只是把它留给编译器,用户会经常得到一个可怕的,无用的错误信息。通过一些自己执行需求的工作,你可以提高这一点。 – 2010-11-02 18:39:56

+0

@Jerry - 这很公平。然而,在我看来,花时间学习理解错误信息会更好。它们不是无用的,只是很难破译。然后,可以将该技能应用于理解其他错误,例如错误使用STL时获得的错误。 – 2010-11-02 18:49:31

回答

1

如果您要强制使用接口,那么为什么要使用模板呢?你可以简单地做 -

class SomeInterface //make this an interface by having pure virtual functions 
{  
    public: 
     RType SomeFunction(Param1 p1, Param2 p2) = 0; 
     /*You don't have to know how this method is implemented, 
      but now you can guarantee that whoever wants to create a type 
      that is SomeInterface will have to implement SomeFunction in 
      their derived class. 
     */ 
}; 

其次

template <class C2> 
class SomeClass 
{ 
    //use SomeInterface here directly.  
}; 

更新 -

这种方法的基本问题是,它仅适用于由用户推出的类型。如果存在符合您的接口规范的标准库类型或符合SomeInterface的类的第三方代码或其他库(如boost),则它们将不起作用,除非将它们包装在自己的类中,接口并适当转发呼叫。我不知何故不喜欢我的答案了。

+0

因为我知道* *我从类想要什么,但不知道该怎么还,所以推迟'hows'只定义'什么-all' – 2010-11-02 18:33:01

+0

这是确定。您将SomeInterface中的函数声明为纯虚函数,从而使其成为纯粹的接口。 – Vatsan 2010-11-02 18:41:54

3

理想情况下,您应该使用concept来指定用作模板参数的类型的要求。不幸的是,即将推出的标准都不包括concept

缺乏这一点,有多种方法可用于执行此类要求。您可能想阅读Eric Neibler's article以了解如何对模板参数执行要求。

我同意埃里克的断言,把它全部留给编译器通常是不可接受的。这是我们大多数人与模板关联的可怕错误消息的来源,在这些错误消息中看似微不足道的错别字会导致无法读取的页面。

+0

感谢您的文章:) – 2010-11-02 22:52:28

+0

一个更多的疑问 - 你知道我怎么能找出代码实际上生成的功能? _if我在模板中有很多fun​​cs,但只使用其中一个(有没有比找到函数更好的方法)_ – 2010-11-02 23:13:44

1

概念,一个现在被遗弃的概念(双关语不打算,但指出)用于描述模板参数必须满足哪些要求缺席,要求才会生效隐含。也就是说,如果你的用户作为一个模板参数不能满足他们,代码将不能编译。不幸的是,由此产生的错误信息往往是相当混乱的。你可以做些什么来改善这方面的唯一一件事就是

  1. 描述模板的文档中的要求
  2. 插入代码检查在你的模板对于那些要求在早期,前深入研究以至于你的用户所获得的错误信息变得无法理解。 后者可能相当复杂(static_assert救援!)甚至不可能,这就是考虑成为核心语言功能而不是图书馆的概念的原因。

注意,很容易忽视的要求这样,当有人使用类型作为模板参数,将无法正常工作,这将仅是显而易见的。但是,至少容易忽视要求往往相当失去并把更多的进入比代码实际上是调用了说明。
例如,+被定义不仅适用于数字,也为std::string和为任意数量的用户定义的类型的。因此,模板add<T>不仅可以与数字一起使用,还可以与字符串和无限数量的用户定义类型一起使用。这是否是您想要抑制的代码的不需要的副作用或您想要支持的功能取决于您。我只是说要抓住这个并不容易。

我不认为有虚函数的抽象基类的形式定义一个接口是一个好主意。这是运行时多态,一个主要的经典OO。如果你这样做,那么你不需要一个模板,只需参考每个基类。
但你也失去了模板的主要优点,这是他们在某些方面,更加灵活(尝试写一个add()功能的经典OO与任何类型的重载在+工作)和更快的一个,因为函数调用的绑定不是在运行时,而是在编译期间进行。 (这使超过它可能看起来像起初由于内联的能力,这通常是不可能的运行时多态性。)

+0

感谢您详细解释,'confusion' - 我这样做,如果我不关心run时间开销?或者它仍然是一种糟糕的设计。这是因为,认为有人在使用之前必须知道要实施什么,并且没有干净的方式让他们知道,(我的知识是有限的,请抛出更多的概念或我可能错过的观点),这很痛苦。 。 – 2010-11-02 23:10:07

+0

@Gollum:嗯,问题是这样的:如果你让这些函数变成虚拟的,为什么还要模板呢?经典的OO运行时多态性将与此一起工作。而且你的模板的用户可能会感到困惑,从你的基类派生的类型_not_也可以工作。国际海事组织,这基本上归结为设计决定。你想要运行时多态还是编译时多态?通常你需要后者的速度(编译时绑定和内联,虚拟杀死)和灵活性(鸭子输入:支持所有“运算符+”超载)的附加内容。 – sbi 2010-11-04 21:32:58

+0

如果你想要后者,你需要后者。当然,将_concepts_推迟到标准的未来版本,编译时多态性缺乏清楚说明用于模板参数需要支持哪些类型的能力。但这就是C++(当前)的方式。如果你想在C++中编译时多态,你需要忍受它。 – sbi 2010-11-04 21:35:27