Реализация pImpl с минимальным количеством кода

Какие трюки можно использовать для минимизации рабочей нагрузки при реализации классов pImpl?

Заголовок:

class Foo {
    struct Impl;
    boost::scoped_ptr<Impl> self;
public:
    Foo(int arg);
    ~Foo();
    // Public member functions go here
};

Реализация:

struct Foo::Impl {
    Impl(int arg): something(arg) {}
    // All data members and private functions go here
};

Foo::Foo(int arg): self(new Impl(arg)) {}
Foo::~Foo() {}

// Foo public functions go here (and they refer to data as self->something)

Как бы вы это улучшили, используя Boost, возможно наследование, CRTP или другие трюки, чтобы избежать как можно большего числа шаблонов? Производительность выполнения не является проблемой.

Ответ 1

Реализация pimpl из Loki может быть хорошим ответом. См. Также статья DDJ об этом.

Ответ 2

Возможно, но наивная реализация - это не то, что вы хотите.

Проблема в том, что шаблоны, как правило, встроены, наивная реализация:

template <class Object>
class Pimpl
{
public:
  explicit Pimpl(Object* obj): mObject(obj) {}
  ~Pimpl() { delete mObject; }

  // either deep copy or no copy
private:
  Object* mObject;
};

Теперь проблема заключается в том, что вы не хотите, чтобы Object был известен в вашем файле заголовка вообще (не для двоичной совместимости, а для управления зависимостями). И если Object неизвестно, вы не можете напрямую реализовать Destructor, Copy Constructor и Assignment Operator...

Проблема далеко не неразрешима! Boost действительно решает его для shared_ptr.

Идея состоит в том, чтобы передать второй элемент в конструкторе, который позаботится о том, чтобы освободить память первого, и который будет снабжен хорошей реализацией по умолчанию.

Это, конечно, работает с косвенностью.

namespace detail {
  template <class Object>
  struct Deleter { virtual void do(Object*) = 0; };
}

template <class Object>
class Pimpl
{
public:
  typedef detail::Deleter<Object> deleter_type;
  typedef boost::shared_ptr<deleter_type> deleter_pointer;

  Pimpl(std::auto_ptr<Object> obj, deleter_pointer del);
  ~Pimpl();
  Pimpl(const Pimpl&);
  Pimpl& operator(const Pimpl&);

private:
  Object* mObject;
  deleter_pointer mDeleter;
};

Это классическая идиома в С++, добавьте еще один уровень косвенности:)