
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.