4

据我了解,pimpl 习惯用法的主要好处是将数据成员隐藏在实现文件中而不是标题中。但是,模板需要在头文件中完全定义,以便编译器按需实例化它们。在这种情况下,将 pimpl 习惯用法用于模板类有什么好处?

4

5 回答 5

5

虽然 pimpl 习惯用法在模板类中使用时并没有真正隐藏任何内容,但它确实允许您轻松编写非抛出交换(尽管使用 C++11 移动语义,这不是一个问题)。

于 2011-09-26T23:29:57.623 回答
1

在大型项目中,单独解耦翻译单元就是 pimpl 的充分理由。这甚至适用于模板:

// main interface

template <typename> struct MyImpl;

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

// implementation

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

// TheInterface implementation
于 2011-09-26T23:31:52.707 回答
1

有一种情况可能不是严格意义上的 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,但它以类似的方式解决了相同的问题。

于 2011-09-27T00:01:47.107 回答
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 习惯用法在模板类上下文中工作。

于 2011-09-27T00:03:04.277 回答
0

它仍然非常有用 - 考虑一个自动或共享指针,它是一个模板,非常适用于解决和实现 PIMPL。是否是最好的解决方案取决于问题。

模板需要在头文件中完全定义,以便编译器按需实例化它们。

您可以声明模板的成员和接口,然后在您的类型的 cpp 文件中,您可以#include对专业化进行必要的定义并在那里使用它们。

于 2011-09-27T00:20:57.177 回答