2011-09-26 79 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的专业化的必要的定义,并利用它们在那里。