1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
#include <iostream>
#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();
void f();
};
int main()
{
Test t;
t.f();
}
template<>
struct PImplMagic<Test>::Impl
{
Impl()
{
std::cout << "It works!" << std::endl;
}
int x = 7;
};
Test::Test()
: std::unique_ptr<Impl>(new Impl)
{
}
void Test::f()
{
std::cout << (*this)->x << std::endl;
}
|
It works!
7 |
http://ideone.com/WcxJu2
Some things to note:
- The static_assert on lines 10 and 11 can't be in class scope because the compiler complains that Derived is not a complete type, so I put it in the constructor body since Derived is a complete type by then
- If you try and do this without
PImplMagic and just directly inherit
std::unique_ptr<Test::Impl> (and have
Impl declared in
Test) it will say that
Test has no member named
Impl (notice it doesn't say
Test is an incomplete type (well, on some older versions of gcc it does)) so I have to have
Impl be defined before
Test - I did this with the
PImplMagic class.
- As you can see, I could not make
Impl private or protected - when referencing it in
std::unique_ptr<PImplMagic<Test>::Impl>, it complains about
Impl being protected. This is fine, though, since there's still no way to access the actual
Impl instance from outside the class.
The whole point of all of this was just for fun to see if I could avoid using a separate member for the impl pointer - as you can see from line 46 the syntax is much more cool than
impl->x
or
this->impl->x
.