It might be nice if the new code included a comment explaining the reasoning.
On Thursday, April 16, 2009, Roman Perepelitsa
2009/4/16 Igor R
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
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.