Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::reference_wrapper does not work nicely with std::bind

Tags:

c++

c++11

I'm trying to emulate perfect/move capturing in C++11 lambdas with std::bind. In the function below I'd like to pass handler with mutable 'operator()' by lvalue or by rvalue, copy or move it as needed and call it.

template <typename Handler>
void foo (Handler&& h)
{
    std::bind (
        [] (Handler& h) { h (); },
        std::forward<Handler> (h)
    ) ();
}

This code works fine in most cases, but fails when I wrap handler with std::ref. http://coliru.stacked-crooked.com/a/b9c29b6ed6fb5aa8

int main ()
{
    int i = 0;
    auto x = [i] () mutable { std::cout << "i=" << ++i << "\n"; };

    foo (x);                // OK
    foo (std::move (x));    // OK
    foo (std::ref (x));     // Error
    return 0;
}

If I create my own 'reference_wrapper' implementation, it works just fine. http://coliru.stacked-crooked.com/a/6b302233ab86d9ad :

template <typename T>
struct my_reference_wrapper
{
    T& t;
    template <typename ...As> auto
    operator() (As&&... args) const -> decltype (t (std::forward<As> (args)...))
    {
        return t (std::forward<As> (args)...);
    }
};

template <typename T> inline my_reference_wrapper<T>
my_ref (T& t) { return { t }; }

int main ()
{
    int i = 0;
    auto x = [i] () mutable { std::cout << "i=" << ++i << "\n"; };

    foo (my_ref (x));     // Now OK
    foo (my_ref (x));     // And even increments 'i' properly.
    return 0;
}

Is it std::bind bug?

Is it possible to make it compile with c++11 and using only std library classes, without reinventing own wrappers?

like image 335
Nikki Chumakov Avatar asked Oct 22 '25 14:10

Nikki Chumakov


1 Answers

std::bind has special handling for std::reference_wrapper.

You may add overload to handle that:

template <typename T>
void foo (std::reference_wrapper<T> h)
{
    std::bind ([] (T& t) { t(); }, h) ();
}

Demo

like image 113
Jarod42 Avatar answered Oct 25 '25 04:10

Jarod42