bind にメンバ関数を渡したときに this 以外のオブジェクトでメンバ関数を呼び出してもらう方法

例えば shared_ptr を this の代わりに使うことができる。

struct Hoge { void foo() { } };
boost::shared_ptr<Hoge> h(new Hoge());
boost::bind(&Hoge::foo, h)();
boost::bind(&Hoge::foo, _1)(h);

でもこれを自前のクラスにしてしまうと、途端に動作しなくなる。

template<class T>
class pointer
{
    T* p_;
public:
    pointer() : p_(0) { }
    pointer(T* p) : p_(p) { }
    T& operator*() const { return *p_; }
    T* operator->() const { return p_; }
    T* get() const { return p_; }
};
pointer<Hoge> h(new Hoge());
boost::bind(&Hoge::foo, h)();   // エラー!
boost::bind(&Hoge::foo, _1)(h); // エラー!

メンバ関数を呼び出す際には当然 this が必要になるんだけど、Hoge& や Hoge* のオブジェクトが現れた場合は、

// <boost/bind/mem_fn_template.hpp> class mf0
R operator()(T& t) const { return (t.*f_)(); }
R operator()(T* p) const { return (p->*f_)(); }

こんな風に普通に呼び出す。でもそうでないオブジェクトの場合は、

template<class U> R call(U& u, T const *) const { return (u.*f_)(); }
template<class U> R call(U& u, void const *) const { return (get_pointer(u)->*f_)(); }

template<class U> R operator()(U & u) const { return call(u, &u); }

こうなる。T* に暗黙にキャスト可能な場合は普通の呼び出し方だけど、そうでないオブジェクト(今回の場合は pointer)だった場合は get_pointer を介してポインタを取得してからメンバを呼び出すようになってる。
つまり pointer クラスのコンパイルを通すには、get_pointer を定義してポインタを返すようにすればいい。

template<class T>
T* get_pointer(const pointer<T>& ptr) { return ptr.get(); }
pointer<Hoge> h(new Hoge());
boost::bind(&Hoge::foo, h)();   // OK
boost::bind(&Hoge::foo, _1)(h); // OK

あと std::auto_ptr でやったらどうなるんだろうと思ってやってみたら、当たり前のようにコンパイルが通った。
調べてみると、 で std::auto_ptr に対する get_pointer が定義されてました。さすが…。