Is there any advantage to the pimpl idiom with a templated class?
It is my understanding that the primary b开发者_运维知识库enefit of the pimpl idiom is to hide the data members in the implementation file instead of the header. However, templates need to be fully defined in the header in order for the compiler to instantiate them on demand. In this case, is there any advantage to using the pimpl idiom for a templated class?
While the pimpl idiom doesn't really hide anything when used in a templated class, it does allow you to easily write non-throwing swaps (although with C++11 move semantics this is less of a concern).
In large projects, decoupling translation units alone is a sufficient reason for pimpl. This works even with templates:
// main interface
template <typename> struct MyImpl;
class TheInterface
{
MyImpl<int> * pimpl;
};
// implementation
#include "MyImpl.hpp" // heavy-weight template library
// TheInterface implementation
Theres one case that may not strictly be a pimpl idiom, but is similar enough to warrant knowing about. That is to have a typesafe template wrapper over a non-typesafe version.
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_;
};
Now any use of MyMap<T>
doesn't need to be exposed to the internals of MapBase, and you only get one implementation of the guts of those functions. I'd also consider making MapBase be an abstract base class to make the decoupling even stronger.
As I said, its not exactly a pimpl, but it solves may of the same issues in a similar way.
I think, if you extend the idiom a bit, you could get at least a bit out of it in some cases. In a template not every operation must necessarily depend on the template parameters. So you can inherit from a Impl
class, that itself uses the pimpl idiom, something like this:
struct FooPimpl;
class FooImpl {
protected:
FooPimpl* pimpl;
public:
void myCommonInterfaceMethod();
};
template <typename T> class Foo : public FooImpl {
// stuff that depends on T
};
Of course, this depends greatly on the circumstances. But I see the pimpl idiom working in a template class context.
it's still quite usable - consider an auto or shared pointer, which is a template and quite usable for solving and implementing PIMPL. whether it's the best solution depends on the problem.
templates need to be fully defined in the header in order for the compiler to instantiate them on demand.
you can declare an the template's members and interface, then in your type's cpp file, you can #include
the necessary definitions of the specializations and use them there.
精彩评论