user1715664
user1715664

Reputation: 153

std::bind and std::weak_ptr

I have a class that creates a wrapper functor to deal with a weak_ptr to an object. When the functor executes, it will test the weak_ptr before invoking the object functor.

Additionally, the wrapper functor can return a default value if the object no longer exists.

This is an excerpt of a class that compiles under GCC 4.4.7...

class Bind
{
public:

    // non-void weak-functor
    template <typename R>
    struct Wrapper<R, typename std::enable_if<!std::is_void<R>::value>::type>
    {
        using result_type = R;

        template <typename O>
        R operator()(const std::weak_ptr<O> && obj,
                     std::function<R()> && func, R && ret)
        {
            if (auto ptr = obj.lock())
            {
                return func();
            }

            return std::forward<R>(ret);
        }
    };

    // weak from shared - non-void return
    template <typename R, typename F, typename O, typename... A>
    static std::function<R()> Weak(R && ret,
                                   F func,
                                   const std::shared_ptr<O> && obj,
                                   A&&... args)
    {
        return std::bind(Wrapper<R>(),
                         std::weak_ptr<O>(obj),
                         std::function<R()>(std::bind(func, obj.get(),
                                            std::forward<A>(args)...)),
                         ret);
    }

    // ...
};

The class can be used like this...

auto x = std::make_shared<X>();
auto f = Bind::Weak(false, &X::foo, x, 1, 2, 3);

f();   // returns x::foo(1, 2, 3) 

x.reset()

f();   // returns false

Unfortunately, after upgrading the compiler to GCC 4.8.3 it no longer compiles. The error starts like this...

error: could not convert 'std::bind(_Func&&, _BoundArgs&& ...)

...with the usual mountain of template crud. The jist is that it can no longer convert the result of std::bind() inside Bind::Weak() into the return type of Bind::Weak().

I've fiddled with this for a few hours now and haven't been able to resolve the issue.

Upvotes: 1

Views: 1315

Answers (1)

rodrigo
rodrigo

Reputation: 98388

The problem is that you cannot do perfect forwarding using a std::function because the std::function is required to be copyable, so the bound values have to be copiable, too.

Changing the operator() prototype to:

template<typename O>
R operator()(const std::weak_ptr<O>& obj, const std::function<R()>& func, const R& ret)
{
    //...
}

Should be more or less enough to make this work (it is difficult to be sure because your posted code is not complete).

But now that your forwarding into the binding is destroyed, all those std::forward and && do not make much sense, IMO.

Upvotes: 1

Related Questions