Is it possible somehow to make a binder that stores "unexpected" argument?
Motivation: I have to create & pass a callback handler from within
intusively ref-counted object (MS-ATL) to an outer asynchronous
subsystem. If the object were shared-ptr enabled, I'd do this as
usually:
ThisObj::handler()
{
//...
}
ThisObj::doSomething()
{
asyncSubsystem_->doSomething(&ThisObj::handler, shared_from_this());
}
However, in my case I have to do something like this:
asyncSubsystem_->doSomething(&ThisObj::handler, this, mySmartPtr); //
store someOtherSmartPtr in the functor, just to ensure "this" won't
die before the handler is invoked
Is it possible with bind, lambda or some other library?
Thanks.
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
Hello,
Is it possible somehow to make a binder that stores "unexpected" argument?
Motivation: I have to create & pass a callback handler from within
intusively ref-counted object (MS-ATL) to an outer asynchronous
subsystem. If the object were shared-ptr enabled, I'd do this as
usually:
ThisObj::handler()
{
//...
}
ThisObj::doSomething()
{
asyncSubsystem_->doSomething(&ThisObj::handler, shared_from_this());
}
However, in my case I have to do something like this:
asyncSubsystem_->doSomething(&ThisObj::handler, this, mySmartPtr); //
store someOtherSmartPtr in the functor, just to ensure "this" won't
die before the handler is invoked
Is it possible with bind, lambda or some other library?
Thanks.
If you don't want or can't overload get_pointer, you can use double bind trick.
CComPtr<ThisObj> self(this);
asyncSubsystem_->doSomething(bind(bind(&ThisObj::handler, this), self));
Great, thank you!
BTW, is it legal to overload get_pointer inside boost namespace or
it's considered a "dirty patch"?
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.
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.
On Thursday, April 16, 2009, Roman Perepelitsa
<roman.pe...@gmail.com> wrote:
> 2009/4/16 Igor R <boost...@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.
>
Wow, very nice idea!
But if you intend to commit this patch to the trunk, please note that
there're 25 more places in this file where the above change should be
done :).