1
\$\begingroup\$

I have started to utilize the PIMPL pattern in my code. I do not have access to C++11 etc. but do have access to Boost. The code must be able to compile on C++03 compilers.

I decided to write a wrapper/helper class that will remove the need for most of the boilerplate code and ensure that objects are automatically cleaned up on destruction of the parent object etc.

template<typename T>
class VRPimpl
{
private:
    const boost::movelib::unique_ptr<T> m_impl;
public:
    VRPimpl();
    VRPimpl(T t);
    ~VRPimpl();

    T& operator*();
    const T& operator*() const;
    T* operator->();
    const T* operator->() const;
};

template<typename T>
VRPimpl<T>::VRPimpl() 
    : m_impl(boost::movelib::make_unique<T>()) { }

template<typename T>
VRPimpl<T>::VRPimpl(T t)
    : m_impl(boost::movelib::make_unique<T>(boost::move(t))) { }

template<typename T>
VRPimpl<T>::~VRPimpl() 
{

}

template<typename T>
T& VRPimpl<T>::operator*()
{
    return *m_impl.get();
}

template<typename T>
const T& VRPimpl<T>::operator*() const
{
    return *m_impl.get();
}

template<typename T>
T* VRPimpl<T>::operator->() 
{
    return m_impl.get();
}

template<typename T>
const T* VRPimpl<T>::operator->() const
{
    return m_impl.get();
}

//1 argument
template<class MaybeMovable, class MaybeRv>
MaybeMovable ConstructPimpl(BOOST_FWD_REF(MaybeRv) x)
{
    return MaybeMovable(boost::forward<MaybeRv>(x));
}

//2 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2>
MaybeMovable ConstructPimpl(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2)
{
    return MaybeMovable(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2));
}

//3 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2, class MaybeRv3>
MaybeMovable ConstructPimpl(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2, BOOST_FWD_REF(MaybeRv3) x3)
{
    return MaybeMovable(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2), boost::forward<MaybeRv3>(x3));
}

//4 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2, class MaybeRv3, class MaybeRv4>
MaybeMovable ConstructPimpl(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2, BOOST_FWD_REF(MaybeRv3) x3, BOOST_FWD_REF(MaybeRv4) x4)
{
    return MaybeMovable(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2), boost::forward<MaybeRv3>(x3), boost::forward<MaybeRv4>(x4));
}

//5 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2, class MaybeRv3, class MaybeRv4, class MaybeRv5>
MaybeMovable ConstructPimpl(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2, BOOST_FWD_REF(MaybeRv3) x3, BOOST_FWD_REF(MaybeRv4) x4, BOOST_FWD_REF(MaybeRv5) x5)
{
    return MaybeMovable(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2), boost::forward<MaybeRv3>(x3), boost::forward<MaybeRv4>(x4), boost::forward<MaybeRv5>(x5));
}

//6 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2, class MaybeRv3, class MaybeRv4, class MaybeRv5, class MaybeRv6>
MaybeMovable ConstructPimpl(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2, BOOST_FWD_REF(MaybeRv3) x3, BOOST_FWD_REF(MaybeRv4) x4, BOOST_FWD_REF(MaybeRv5) x5, BOOST_FWD_REF(MaybeRv6) x6)
{
    return MaybeMovable(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2), boost::forward<MaybeRv3>(x3), boost::forward<MaybeRv4>(x4), boost::forward<MaybeRv5>(x5), boost::forward<MaybeRv6>(x6));
}

As can be seen above I have also added some helpers that allow us to easily create an object and forward on the parameters.

The use case can then be as follows

class PimplTest
{
public:
    PimplTest();
    PimplTest(int test);
    PimplTest(int test, std::string test2);

    void Print();

private:
    class PimplImplTest;
    VRPimpl<PimplImplTest> m_impl;
};

class PimplTest::PimplImplTest
{
public:
    PimplTest::PimplImplTest() : 
        m_test(-1),
        m_test2("Unknown")
    {

    }

    PimplTest::PimplImplTest(int test) : 
        m_test(test),
        m_test2("Unknown")
    {

    }

    PimplTest::PimplImplTest(int test, std::string test2) :
        m_test(test),
        m_test2(test2)
    {

    }

    void Print()
    {
        std::cout << m_test << "," << m_test2 << std::endl;
    }

private:
    int m_test;
    std::string m_test2;
};

PimplTest::PimplTest() : 
    m_impl()
{

}

PimplTest::PimplTest(int test) :
m_impl(ConstructPimpl<PimplTest::PimplImplTest>(test))
{

}

PimplTest::PimplTest(int test, std::string test2) :
m_impl(ConstructPimpl<PimplTest::PimplImplTest>(test, test2))
{

}

void PimplTest::Print()
{
    m_impl->Print();
}

int main()
{
    PimplTest test;
    test.Print();

    PimplTest test2(19);
    test2.Print();

    PimplTest test3(24, "Test");
    test3.Print();
}

Is there anything I can improve on or fix?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.