Boost logo

Boost :

Subject: Re: [boost] pimpl library proposal
From: Michael Bailey (jinxidoru_at_[hidden])
Date: 2010-12-04 16:38:33


On Dec 3, 2010, at 8:26 PM, Phil Endecott wrote:
> which really isn't much different in terms of the amount of typing,
> except for the forwarding. Can you show what your BOOST_PIMPL_METHOD
> expands to? I can't immediately guess how you manage to not tell it
> all the argument and return types.

First of all, thanks for your input. I appreciate it. I will post the source below, so as to not clutter the conversation.

> Re using the shared_ptr, this mainly gains the safety of otherwise
> forgetting to implement the dtor, and has speed and space
> disadvantages. I'm not convinced that is really useful, and so I would
> decouple it from the concise forwarding feature.

I think that the value comes in avoiding the pitfall of forgetting to free the pointer, as per all smart pointer implementations. That said, you're right in pointing out that shared_ptr just adds overhead. I think a preferable method, after taking in your considerations, is to just have the boost::pimpl<> class manage the allocating and freeing directly with new/delete. This does not add any overhead, but still gives the same safety of shared_ptr.

You actually bring up an interesting idea. Perhaps the forwarding should be decoupled (which would not be hard at all) and generalized, rather than pushing the user into the pimpl paradigm. The user could easily use the forwarding for pimpl implementations or for something completely different.

> Generally, I think that implementing pimpls falls more into the
> category of stuff that's best done with some sort of tool, e.g. a
> "pimpl wizzard" in your IDE, rather than a library.

---- boost/pimpl.hpp ----

#include <boost/typeof/typeof.hpp>
#include <boost/type_traits/function_traits.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>

namespace boost {

template <typename T>
class pimpl {
public:

    typedef T* ptr_type;

    pimpl( ptr_type p = new T() )
    : m_impl( p )
    {}

    ~pimpl() {
        delete m_impl;
    }

protected:

    T& impl() { return *m_impl; }
    const T& impl() const { return *m_impl; }

private:
    ptr_type m_impl;
};

template <typename T>
struct method_traits;

#ifndef BOOST_METHOD_TRAITS_LIMIT
# define BOOST_METHOD_TRAITS_LIMIT 10
#endif

#define BOOST_METHOD_TRAITS(z,n,data) \
    template <typename C, typename R \
        BOOST_PP_ENUM_TRAILING_PARAMS_Z(z,n,class T) > \
    struct method_traits< R(C::*)( BOOST_PP_ENUM_PARAMS_Z(z,n,T) ) data > \
    : public function_traits< R( BOOST_PP_ENUM_PARAMS_Z(z,n,T) ) > { \
        typedef data C class_type; \
    };

BOOST_PP_REPEAT(BOOST_METHOD_TRAITS_LIMIT,BOOST_METHOD_TRAITS,)
BOOST_PP_REPEAT(BOOST_METHOD_TRAITS_LIMIT,BOOST_METHOD_TRAITS,const)
BOOST_PP_REPEAT(BOOST_METHOD_TRAITS_LIMIT,BOOST_METHOD_TRAITS,volatile)
BOOST_PP_REPEAT(BOOST_METHOD_TRAITS_LIMIT,BOOST_METHOD_TRAITS,const volatile)

}

#define BOOST_PIMPL_CTOR( cls ) \
    cls::cls() {}

#define BOOST_PIMPL_DEFINE_METHOD_M( z, n, data ) \
    BOOST_JOIN(BOOST_JOIN(data::arg,n),_type) BOOST_JOIN(a,n)

#define BOOST_PIMPL_METHOD( args, cls, meth, ... ) \
    ::boost::method_traits< BOOST_TYPEOF(&cls::meth) >::result_type \
        cls::meth( \
            BOOST_PP_ENUM_SHIFTED( BOOST_PP_INC(args), \
                BOOST_PIMPL_DEFINE_METHOD_M, \
                ::boost::method_traits<typeof(&cls::meth)> \
            ) \
        ) __VA_ARGS__ { \
            return impl().meth( \
                BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(args),a) \
            ); \
        }


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk