2009/4/16 Igor R <boost.lists@gmail.com>
Well, it turns out that defining get_pointer() for ATL::CComPtr won't
help, because CComPtrBase defines its own operator&(), doing this in a
pretty weird way (quote from atlcomcli.h):

       //The assert on operator& usually indicates a bug.  If this is really
       //what is needed, however, take the address of the p member explicitly.
       T** operator&() throw()
       {
               ATLASSERT(p==NULL);
               return &p;
       }

So the "double bind" is the only short way to do this.

Ah, I see why it happens. To distinguish between regular objects and smart pointers, mem_fn does the following trick:
  void call(const T*) { /* it's a regular object */ }
  void call(const void*) { /* it might be a smart pointer */ }
  void test(U& t) { call(&t); }

If U is CComPtr<T>, taking its address triggers an assert. It can be easily fixed though.
  void test(U& t) { call(false ? &t : 0); }

Now type of the expression &t is used for choosing the right overload of call, but operator& is not applied in runtime.

Here's the patch against trunk:
--- mem_fn_template.hpp (revision 52422)
+++ mem_fn_template.hpp (working copy)
@@ -51,14 +51,14 @@

     template<class U> R operator()(U & u) const
     {
-        BOOST_MEM_FN_RETURN call(u, &u);
+        BOOST_MEM_FN_RETURN call(u, false ? &u : 0);
     }

 #ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS

     template<class U> R operator()(U const & u) const
     {
-        BOOST_MEM_FN_RETURN call(u, &u);
+        BOOST_MEM_FN_RETURN call(u, false ? &u : 0);
     }

 #endif

And here is the test:
#include <cstdlib>
#include <boost/bind.hpp>

struct foo
{
  void bar() {}
} f;

struct ptr
{
  void* operator&() { std::abort(); }
};

foo* get_pointer(const ptr& p) { return &f; }

int main() {
  boost::bind(&foo::bar, ptr())();
}

Roman Perepelitsa.