
Implementing operator->* For Smart Pointers
by Scott Meyers

Listing One
class Wombat {          // wombats are cute Australian marsupials
public:                 // that look something like dogs

    int dig();          // return depth dug
    int sleep();        // return time slept
};

typedef int (Wombat::*PWMF)(); // PWMF--a pointer to a Wombat member
function
Wombat *pw = new Wombat;

PWMF pmf = &Wombat::dig;   // make pmf point to Wombat::dig
(pw->*pmf)();              // same as pw->dig();
pmf = &Wombat::sleep;      // make pmf point to Wombat::sleep
(pw->*pmf)();              // same as pw->sleep();


Listing Two
class PMFC {               // "Pending Member Function Call"
public:
    ...
    return type operator()( parameters ) const;
    ...
};

template<typename T>        // template for smart ptrs-to-T
class SP {                  // supporting operator->*
public:
    ...
    const PMFC operator->*( return type (T::*pmf)( parameters ) ) const;
    ...
};

Listing Three
class PMFC {
public:
    ...
    return type operator()() const;
    ...
};

template<typename T>
class SP {
public:
   ...
    const PMFC operator->*( return type (T::*pmf)() ) const;
    ...
};

Listing Four
template<typename ReturnType>   // template for a pending mbr func
class PMFC {                    // call returning type ReturnType
public:
    ...
    ReturnType operator()() const;
    ...
};

template<typename T>
class SP {
public:
    ...
    template<typename ReturnType>
        const PMFC<ReturnType>
            operator->*( ReturnType (T::*pmf)() ) const;
    ...
};

Listing Five
template<typename ObjectType,        // class offering the mem func
         typename ReturnType,        // return type of the mem func
         typename MemFuncPtrType>    // full signature of the mem func
class PMFC {
public:
    typedef std::pair<ObjectType*, MemFuncPtrType> CallInfo;

    PMFC(const CallInfo& info): callInfo(info) {}
    ReturnType operator()() const
        { return (callInfo.first->*callInfo.second)(); }
private:
    CallInfo callInfo;
};

Listing Six
template <typename T>
class SP {
public:
    SP(T *p): ptr(p) {}

    template <typename ReturnType>
        const PMFC<T, ReturnType, ReturnType (T::*)()>
            operator->*(ReturnType (T::*pmf)()) const
                { return std::make_pair(ptr, pmf); }
    ...
private:
    T* ptr;
};

Listing Seven
#include <iostream>
#include <utility>
using namespace std;

template<typename ObjectType, typename ReturnType, typename MemFuncPtrType>

class PMFC { ... };              // as above

template <typename T>            // also as above
class SP { ... };

class Wombat {
public:
    int dig()
    {
        cout << "Digging..." << endl;
        return 1;
    }
    int sleep()
    {
        cout << "Sleeping..." << endl;
        return 5;
    }
};

int main()
{                                     // as before, PWMF is a
    typedef int (Wombat::*PWMF)();    // pointer to a Wombat member
function

    SP<Wombat> pw = new Wombat;

    PWMF pmf = &Wombat::dig;   // make pmf point to Wombat::dig
    (pw->*pmf)();              // invokes our operator->*;
                               // prints "Digging..."

    pmf = &Wombat::sleep;      // make pmf point to Wombat::sleep
    (pw->*pmf)();              // invokes our operator->*;
}                              // prints "Sleeping..."

Listing Eight
template <typename T>
class SP {
public:
    ...                     // as above

    template <typename ReturnType>
        const PMFC<T, ReturnType, ReturnType (T::*)() const>  // const
added
            operator->*(ReturnType (T::*pmf)() const) const   // const
added
                { return std::make_pair(ptr, pmf); }

    ...                     // as above
};

Listing Nine
template <typename ObjectType, typename ReturnType, typename
MemFuncPtrType>
class PMFC {
public:
    typedef pair<ObjectType*, MemFuncPtrType> CallInfo;

    PMFC(const CallInfo& info)
   : callInfo(info) {}

    // support for 0 parameters
    ReturnType operator()() const
        { return (callInfo.first->*callInfo.second)(); }

    // support for 1 parameter
    template <typename Param1Type>
        ReturnType operator()(Param1Type p1) const
            { return (callInfo.first->*callInfo.second)(p1); }
private:
    CallInfo callInfo;
};

template <typename T>
class SP {
public:
    SP(T *p): ptr(p) {}

    // support for 0 parameters
    template <typename ReturnType>
        const PMFC<T, ReturnType, ReturnType (T::*)()>
            operator->*(ReturnType (T::*pmf)()) const
                { return std::make_pair(ptr, pmf); }

    // support for 1 parameter
    template <      typename ReturnType, typename Param1Type>
        const PMFC<T, ReturnType, ReturnType (T::*)(Param1Type)>
            operator->*(ReturnType (T::*pmf)(Param1Type)) const
                { return std::make_pair(ptr, pmf); }
    ...
private:
    T* ptr;
};

Listing Ten
template <typename T>   // base class for smart pointers wishing
class SmartPtrBase {    // to support operator->*
public:
    SmartPtrBase(T *initVal): ptr(initVal) {}

    // support for 0 parameters
    template <typename ReturnType>
        const PMFC<T, ReturnType, ReturnType (T::*)()>
            operator->*(ReturnType (T::*pmf)()) const
                { return std::make_pair(ptr, pmf); }

    // support for 1 parameter
    template <   typename ReturnType, typename Param1Type>
        const PMFC<T, ReturnType, ReturnType (T::*)(Param1Type)>
            operator->*(ReturnType (T::*pmf)(Param1Type)) const
                { return make_pair(ptr, pmf); }
    ...
protected:
    T* ptr;
};

Listing Eleven
template <typename T>
class SP: private SmartPtrBase<T> {
public:
    SP(T *p ): SmartPtrBase<T>(p) {}

    using SmartPtrBase<T>::operator->*;    // make the privately inherited
                                           // operator->* templates public

    // normal smart pointer functions would go here;  operator->*
    // functionality is inherited
};

Listing Twelve
template <typename T>                       // traits class
struct MemFuncTraits {};

template <typename R, typename O>           // partial specialization
struct MemFuncTraits<R (O::*)()> {          // for zero-parameter
    typedef R ReturnType;                   // non-const member
    typedef O ObjectType;                   // functions
};

template <typename R, typename O>           // partial specialization
struct MemFuncTraits<R (O::*)() const> {    // for zero-parameter
    typedef R ReturnType;                   // const member
    typedef O ObjectType;                   // functions
};

template <typename R, typename O, typename P1>  // partial specialization
struct MemFuncTraits<R (O::*)(P1)> {            // for one-parameter
    typedef R ReturnType;                       // non-const member
    typedef O ObjectType;                       // functions
};

template <typename R, typename O, typename P1> // partial specialization
struct MemFuncTraits<R (O::*)(P1) const> {     // for one-parameter
    typedef R ReturnType;                      // const member
    typedef O ObjectType;                      // functions
};

Listing Thirteen
template <typename MemFuncPtrType>
class PMFC {
public:
    typedef typename MemFuncTraits<MemFuncPtrType>::ObjectType ObjectType;
    typedef typename MemFuncTraits<MemFuncPtrType>::ReturnType ReturnType;

    ...                 // same as before
};

Listing Fourteen
template <typename MemFuncPtrType>
const PMFC<MemFuncPtrType>
operator->*(MemFuncPtrType pmf) const
{ return std::make_pair(ptr, pmf); }



