0

I'm attempting to create a cleaner header file for reference/documentation of header classes while still recognizing the convenience of templates. So I've got a quick .h / .hpp file

// mempool.h
namespace internal {
  template<typename T,template<class> class Allocator>
  class MemoryPool;
}

template<typename T,template<class> class Allocator = std::allocator>
class MemoryPool
{
  private: internal::MemoryPool<T,Allocator> *pimpl;

  public: MemoryPool();
  public: virtual ~MemoryPool();

  public: void  flush()        { return pimpl->flush();      }
  public: T    *find(T object) { return pimpl->find(object); }
  public: T    *pop()          { return pimpl->pop();        }
  public: void  push(T object) { return pimpl->push(object); }
};

Nice and clean. Then a .hpp file

// mempool.hpp
#include <memory>
#include <mutex>

namespace cext {
namespace memory {
#include "memorypool.h"

template<typename T,template<class> class Allocator>
MemoryPool<T,Allocator>::MemoryPool()
:pimpl(new internal::MemoryPool<T,Allocator>())
{

}

template<typename T,template<class> class Allocator>
MemoryPool<T,Allocator>::~MemoryPool()
{
  delete pimpl;
}

namespace internal {

template<typename T,template<class> class Allocator = std::allocator>
class MemoryPool
{
  private: std::mutex mtx;
  private: Allocator<T> alloc;

  public: MemoryPool()
  :alloc()
  {
  //alloc.allocate(256); 
  }  

  public: ~MemoryPool()
  {
  //alloc.deallocate();  
  }  

  public: void flush()
  {
    mtx.lock();

    puts("flush");

    mtx.unlock();
  }
  public: T *find(T object)
  {
    mtx.lock();

    puts("find");

    mtx.unlock();
    return nullptr;
  }
  public: T *pop()
  {
    mtx.lock();

    puts("pop");

    mtx.unlock();
    return nullptr;
  }

  public: void push(T object)
  {
    mtx.lock();

    puts("push");

    mtx.unlock();
  }
};

} // end internal
} // end cext
} // end memory

So I don't think using pimpl did anything for me since users would need to #include the .hpp file. Changes to implementation would cause linker updates so no compile speed boost, if I'm not mistaken. I could probably do away with the pimpl all together given how I am #including the .h file in the .hpp file.

Q: I'd like to know if there is a clean way to display a minimal header for a template as I've done above in the .h file, but still get some compiler speed-up's? I'm not set on pimpl if there are other methodologies that work.

-Cheers

Seth Hays
  • 311
  • 2
  • 11
  • http://msdn.microsoft.com/en-us/library/by56e477(v=vs.80).aspx – John Zwinck Jun 11 '13 at 07:21
  • 1
    See [this question and accepted answer](http://stackoverflow.com/questions/1724036/splitting-templated-c-classes-into-hpp-cpp-files-is-it-possible?rq=1) to see how this is not possible with templated classes. – congusbongus Jun 11 '13 at 07:22
  • @John Zwinck Thanks but the article didn't get into what I'm after. – Seth Hays Jun 11 '13 at 15:21
  • @Cong Xu Yes I think that question is slightly different since the user is trying to split declaration and definition of a template file. My attempt is to create a separate interfacing class to a template class. I think Willj is on to something below. – Seth Hays Jun 11 '13 at 15:24

1 Answers1

0

If you need to support implicit instantiation of your template for an unknown set of types, you must make the implementation of the template visible to the compiler.

However, there is a useful template technique similar to pimpl that I've used in a similar scenario. This involves 'lifting' the implementation of the template that does not depend on the types of the template parameters into a separate class. Here's an example based on your problem - modified slightly to match the way I would implement a pool allocator:

namespace internal {

  class MemoryPool
  {
    public:
    // allocates up to 'count' blocks big enough to hold 'size' from 'storage'
    MemoryPool(std::size_t size, std::size_t count, void* storage);
    void* allocate(); // allocates a block big enough to hold 'size'
    void deallocate(void* p); // deallocates the block pointed at by 'p'
  };
}

template<typename T,template<class> class Allocator = std::allocator>
class MemoryPool : Allocator<T>, internal::MemoryPool
{
  typedef Allocator<T> Alloc;

  public: MemoryPool(std::size_t n, const Alloc& a = Alloc())
    : Alloc(a), internal::MemoryPool(sizeof(T), n, Alloc::allocate(n))
  {
  }
  public: ~MemoryPool();

  public: T    *poolNew(T object)
  {
    T* p = static_cast<T*>(internal::MemoryPool::allocate());
    Alloc::construct(p, object);
    return p;
  }
  public: void  poolDelete(T* p)
  {
    Alloc::destroy(p);
    return internal::MemoryPool::deallocate(p);
  }
};

This has the desired effect of allowing the implementation of internal::MemoryPool to be hidden in the .cpp.

willj
  • 2,991
  • 12
  • 24
  • So essentially taking the template off of the internal class right? And I suppose that given the external portion of the class is already template'd there is no real reason to also template the internal class. I'll leave the Q open a bit longer to see if there are other methodologies. Thanks your answer was very helpful. – Seth Hays Jun 11 '13 at 15:32