2011-09-26 84 views
4

我的理解是,pimpl習語的主要好處是將數據成員隱藏在實現文件中而不是頭中。然而,模板需要在頭文件中完全定義,以便編譯器按需實例化它們。在這種情況下,對模板類使用pimpl習語有什麼好處?模板類的pimpl習語有沒有優勢?

回答

5

儘管pimpl習語在模板類中使用時沒有真正隱藏任何東西,但它確實允許您輕鬆地編寫非拋棄交換(儘管使用C++ 11移動語義這不是一個問題)。

+1

+1完全忘了這一點。除了不拋光清潔之外,這也是交換的效率優勢。這也適用於移動語義,因爲不透明的類不像移動類型那樣容易移動。 –

+1

接受,因爲這似乎是唯一的真正好處。 –

1

在大型項目中,單獨解耦翻譯單元是pimpl的充分理由。這與模板工程,甚至:

// main interface 

template <typename> struct MyImpl; 

class TheInterface 
{ 
    MyImpl<int> * pimpl; 
}; 

// implementation 

#include "MyImpl.hpp" // heavy-weight template library 

// TheInterface implementation 
+0

但是,如果'TheInterface'是一個模板,這是行不通的,對吧? –

+1

雖然您可以將主模板的實現與類定義分開,並在該TU中使用顯式實例化,但並不完美。儘管如此,如果您有少量的固定數量的模板參數,這樣做纔有意義。但否則整個pimpl想法可能不適合。 –

+0

在大型項目中,pimpl習語是使項目更大的好方法。其結果是一種用C++編碼的C#程序,在這種情況下,直接轉換到C#而不是pimling會更好。請注意,pimpl習語的編譯速度改進在預編譯頭文件已經保留的地方是無用的。 ** pimpl是反C++ ** –

1

的Theres一個情況下,可能不嚴格是PIMPL方法,但足夠相似,以保證寂寂。那就是在非安全類型上有一個類型安全的模板包裝。

class MapBase 
{ 
    public: 
    void* getForKey(const std::string & k); 
    void setForKey(const std::string & k, void * v); 
    ... 
}; 

template<typename T> 
class MyMap 
{ 
    public: 
    T* getForKey(const std::string &k) { return (T*)base_.getForKey(k); } 
    void setForKey(const std::string &k, const T* v) { base_.setForKey(k, T*v); } 
    private: 
    MapBase base_; 
}; 

現在,任何使用MyMap<T>並不需要暴露於MapBase的內部,你只能得到一個實現這些功能的膽量的。我還會考慮讓MapBase成爲一個抽象的基類,以使解耦更強。

正如我所說,它不完全是一個pimpl,但它解決了可能以相似的方式相同的問題。

0

我認爲,如果你延伸了一下成語,在某些情況下你至少可以得到一點點。在模板中,並不是每個操作都必須依賴於模板參數。所以,你可以從一個Impl類繼承,本身使用PIMPL方法,像這樣:

struct FooPimpl; 

class FooImpl { 
    protected: 
    FooPimpl* pimpl; 
    public: 
    void myCommonInterfaceMethod(); 
}; 

template <typename T> class Foo : public FooImpl { 
    // stuff that depends on T 
}; 

當然,這在很大程度上取決於環境。但我看到pimpl習語在模板類上下文中工作。

0

它仍然非常有用 - 考慮一個自動或共享指針,這是一個模板,可用於解決和實現PIMPL。這是否是最好的解決方案取決於問題。

模板需要在標題中完全定義,以便編譯器按需實例化它們。

,你可以在你的類型的CPP文件中聲明的模板的成員和接口的話,你可以#include的專業化的必要的定義,並利用它們在那裏。