5

The traditional PImpl Idiom is like this:

#include <memory>

struct Blah
{
    //public interface declarations

private:
    struct Impl;
    std::unique_ptr<Impl> impl;
};

//in source implementation file:

struct Blah::Impl
{
    //private data
};
//public interface definitions

However, for fun, I tried to use composition with private inheritance instead:

[Test.h]

#include <type_traits>
#include <memory>

template<typename Derived>
struct PImplMagic
{
    PImplMagic()
    {
        static_assert(std::is_base_of<PImplMagic, Derived>::value,
                      "Template parameter must be deriving class");
    }
//protected: //has to be public, unfortunately
    struct Impl;
};

struct Test : private PImplMagic<Test>,
              private std::unique_ptr<PImplMagic<Test>::Impl>
{
    Test();
    ~Test();
    void f();
};

[first translation unit]

#include "Test.h"
int main()
{
    Test t;
    t.f();
}

[second translation unit]

#include <iostream>
#include <memory>

#include "Test.h"

template<>
struct PImplMagic<Test>::Impl
{
    Impl()
    {
        std::cout << "It works!" << std::endl;
    }
    int x = 7;
};

Test::Test()
: std::unique_ptr<Impl>(new Impl)
{
}

Test::~Test() // required for `std::unique_ptr`'s dtor
{}

void Test::f()
{
    std::cout << (*this)->x << std::endl;
}

http://ideone.com/WcxJu2

I like the way this alternate version works, however I'm curious if it has any major drawbacks over the traditional version?

EDIT: DyP has kindly provided yet another version, which is even 'prettier'.

dyp
  • 38,334
  • 13
  • 112
  • 177
LB--
  • 2,506
  • 1
  • 38
  • 76
  • 1
    Your solution is clever, sure, but it's already more verbose than the usual PImpl idiom, for what gain? Now what if you want to define eg. `operator ->` for your `Test` class? You'll have to disambiguate it everywhere... Not quite practical IMHO. – syam Oct 01 '13 at 20:34
  • You might get more attention on [Code Review](http://codereview.stackexchange.com/). – dyp Oct 01 '13 at 21:18
  • 2
    I think you can also get rid of the direct multiple inheritance for `Test`. [Live example](http://coliru.stacked-crooked.com/a/35dcf4a7b0b7a677) – dyp Oct 01 '13 at 21:32
  • 1
    This does not work. You need an explicit destructor in foo (did you even test it with multiple TUs ?). Anyway, this adds nothing to normal pimpl, except that you are using private inheritance to perform composition (btw you need only to inherit from the unique_ptr) – Alexandre C. Oct 01 '13 at 21:39
  • @syam - I'm talking about major drawbacks, not something you can obviously fix. @ DyP - thanks! I'll check out Code Review and I'll also examine that example you provided. @ Alexandre - I'm not sure what you mean? And why do I only need to inherit from unique_ptr? – LB-- Oct 01 '13 at 22:28
  • @LB-- You need to define an out-of-line dtor for `Test`, because the dtor (of `unique_ptr`) requires `Impl` to be a complete type as well. – dyp Oct 01 '13 at 22:50
  • So this is a private curiously reoccurring template with a privately inherited pointer to the implementation? http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern – Dominique McDonnell Oct 01 '13 at 23:24
  • @DominicMcDonnell essentially, yes. You can see my working code [here](https://github.com/LB--/jsonpp/blob/master/src/util/PImpl.hpp). – LB-- Oct 02 '13 at 02:25

1 Answers1

0

From what I understand, one of the reasons to use a pimpl idiom is to hide functionality details from the user of your interface. In your composition with private inheritance example, I believe you are exposing your implementation details to the user.

aligardezi
  • 11
  • 1
  • Nope, though that isn't clear in the OP. The part after `main` (plus a required explicit dtor) can be in a different TU. – dyp Oct 16 '13 at 18:22