我的理解是,pimpl习惯用法的主要好处是隐藏实现文件中的数据成员而不是标题。但是,模板需要在头文件中完全定义,以便编译器按需实例化它们。在这种情况下,对于模板化的类使用pimpl习语有什么好处吗?
答案 0 :(得分:5)
虽然pimpl习惯用法在模板化类中使用时并没有真正隐藏任何东西,但它确实允许你轻松编写非投掷交换(虽然使用C ++ 11移动语义这不是一个问题)。
答案 1 :(得分:1)
在大型项目中,单独解耦翻译单元是pimpl的充分理由。这甚至适用于模板:
// main interface
template <typename> struct MyImpl;
class TheInterface
{
MyImpl<int> * pimpl;
};
// implementation
#include "MyImpl.hpp" // heavy-weight template library
// TheInterface implementation
答案 2 :(得分: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,但它以类似的方式解决了同样的问题。
答案 3 :(得分: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习语在模板类上下文中工作。
答案 4 :(得分:0)
它仍然非常实用 - 考虑一个自动或共享指针,这是一个模板,非常适用于解决和实现PIMPL。它是否是最佳解决方案取决于问题。
模板需要在头文件中完全定义,以便编译器根据需要实例化它们。
你可以声明模板的成员和接口,然后在你的类型的cpp文件中,你可以#include
必要的专业定义并在那里使用它们。