2011-10-22 80 views
11

我想使用pimpl成語,以避免我的圖書館的用戶需要我們的外部依賴(如提升等),但是當我的類模板,似乎是不可能的,因爲方法必須在頭。有什麼我可以做的呢?pimpl爲模板類

回答

7

如果這個類是模板化的,那麼你的用戶基本上需要編譯它(這在最廣泛使用的C++實現中實際上是真的),所以它們需要你的外部依賴。

最簡單的解決方案是將類的大部分實現放在非模板基類(或某些類的封裝成員對象)中。在那裏解決模塊隱藏問題。

然後編寫派生(或包含)類的模板,爲其添加類型安全性。

例如,假設你有一個模板,提供了驚人的能力,分配在第一次訪問(省略了必要的拷貝構造函數,賦值函數,析構):

template <class T> 
class MyContainer 
{ 
    T *instance_; 

public: 
    MyContainer() : instance_(0) {} 

    T &access() 
    { 
     if (instance_ == 0) 
      instance_ = new T(); 

     return *instance_; 
    } 
}; 

如果你想要的「邏輯」被分離成一個非模板基類,你必須進行參數的非模板的方式,這是說的行爲,使用虛擬功能:

class MyBase 
{ 
    void *instance_; 

    virtual void *allocate() = 0; 

public: 
    MyBase() : instance_(0) {} 

    void *access() 
    { 
     if (instance_ == 0) 
      instance_ = allocate(); 

     return instance_; 
    } 
}; 

那麼你可以添加類型意識在外層:

template <class T> 
class MyContainer : MyBase 
{ 
    virtual void *allocate() 
     { return new T(); } 

public: 
    T &access() 
     { return *(reinterpret_cast<T *>(MyBase::access())); } 
}; 

即使用虛擬函數來允許模板「填寫」依賴於類型的操作。顯然,如果你有一些值得隱藏的業務邏輯,這種模式纔有意義。

+0

我覺得這個方法可能是也非常有用,如果你不想讓你的預處理器定義('#define'),常數等。可見。作爲一名開發人員,我不想看到我正在使用的類/庫的實現細節,特別是在自動完成列表中。即使您的業務邏輯不值得隱藏,您也可能希望隱藏這些內容。 – mostruash

1

您可以顯式實例化源文件中的模板,但只有在知道模板類型將會是什麼時纔有可能。否則,不要使用pimpl成語來表示模板。

事情是這樣的:

header.hpp:

#ifndef HEADER_HPP 
#define HEADER_HPP 

template< typename T > 
class A 
{ 
    // constructor+methods + pimpl 
}; 

#endif 

source.cpp:

#include "header.hpp" 

// implementation 

// explicitly instantiate for types that will be used 
template class A<int>; 
template class A<float>; 
// etc... 
+0

-1不要將'auto_ptr'用於PIMPL(它的**未定義行爲**用不完整類型實例化'auto_ptr')。如果你爲外部類定義了構造函數和析構函數,它確實會起作用。但在這種情況下,你不需要智能指針。 –

+0

@ AlfP.Steinbach unique_ptr?或者只是一個原始指針? –

+1

是的,都OK(雖然我不確定在這種情況下如何使用'unique_ptr'的細節;我只會使用'shared_ptr'並接受開銷,因爲不需要人們在標準)。乾杯, –

1

一般有兩種解決方案:

  • 而接口取決於如此我輸入了T,它按照更弱的類型實現(例如,一個使用void*指針直接或槽式擦除),或者

  • 您只支持特定且數量有限的類型。

第二種解決方案與例如, char/wchar_t-依賴的東西。

第一種解決方案在C++模板的早期非常普遍,因爲那時編譯器不擅長識別生成的機器代碼中的共同點,並且會引入所謂「代碼膨脹」。今天,任何嘗試新手的人都會驚訝,模板化解決方案的機器代碼足跡通常比依賴運行時多態性的解決方案要小。當然,YMMV。

乾杯&心連心,

+0

有人試圖編輯建議刪除「直接或通過類型擦除」闡述和「特定和...」資格。闡述對於意義是必要的,並且對於正確性來說資格是必需的。目前被接受爲解決方案的答案是「直接」的一個例子。目前還沒有「類型刪除」的例子,唯一值得一提的是這個答案;如果某人成功刪除了該文件,那將是一件恥辱。 –