2010-11-02 43 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