33

I want to pass an rvalue through std::bind to a function that takes an rvalue reference in C++0x. I can't figure out how to do it. For example:

#include <utility>
#include <functional>

template<class Type>
void foo(Type &&value)
{
    Type new_object = std::forward<Type>(value);    // move-construct if possible
}

class Movable
{
public:
    Movable(Movable &&) = default;
    Movable &operator=(Movable &&) = default;
};

int main()
{
    auto f = std::bind(foo<Movable>, Movable());
    f();    // error, but want the same effect as foo(Movable())
}
David G
  • 94,763
  • 41
  • 167
  • 253
Timothy003
  • 2,348
  • 5
  • 28
  • 33

5 Answers5

36

The reason this fails is because when you specify foo<Movable>, the function you're binding to is:

void foo(Movable&&) // *must* be an rvalue
{
}

However, the value passed by std::bind will not be an rvalue, but an lvalue (stored as a member somewhere in the resulting bind functor). That, is the generated functor is akin to:

struct your_bind
{
    your_bind(Movable arg0) :
    arg0(arg0)
    {}

    void operator()()
    {
        foo<int>(arg0); // lvalue!
    }

    Movable arg0;
};

Constructed as your_bind(Movable()). So you can see this fails because Movable&& cannot bind to Movable.†

A simple solution might be this instead:

auto f = std::bind(foo<Movable&>, Movable());

Because now the function you're calling is:

void foo(Movable& /* conceptually, this was Movable& &&
                        and collapsed to Movable& */)
{
}

And the call works fine (and, of course, you could make that foo<const Movable&> if desired). But an interesting question is if we can get your original bind to work, and we can via:

auto f = std::bind(foo<Movable>,
            std::bind(static_cast<Movable&&(&)(Movable&)>(std::move<Movable&>),
                Movable()));

That is, we just std::move the argument before we make the call, so it can bind. But yikes, that's ugly. The cast is required because std::move is an overloaded function, so we have to specify which overload we want by casting to the desired type, eliminating the other options.

It actually wouldn't be so bad if std::move wasn't overloaded, as if we had something like:

Movable&& my_special_move(Movable& x)
{
    return std::move(x);
}


auto f = std::bind(foo<Movable>, std::bind(my_special_move, Movable()));

Which is much simpler. But unless you have such a function laying around, I think it's clear you probably just want to specify a more explicit template argument.


† This is different than calling the function without an explicit template argument, because explicitly specifying it removes the possibility for it to be deduced. (T&&, where T is a template parameter, can be deduced to anything, if you let it be.)

Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • Thanks. I'm indeed trying to do the latter (passing the rvalue to foo as an rvalue to enable move semantics). I was hoping for something like an `std::ref` for rvalue references, though; the bind your last solution is still a bit too long, and the nested bind is distracting. – Timothy003 Feb 02 '11 at 07:18
  • @Timothy: Well having an rvalue `int` really isn't that useful, it's still just an `int`. Are you working with a more complex type? If so, maybe you might edit your question to make clear what you're hoping for. (If it is the case, I think there may be a misunderstanding on the canonical usage of move semantics; don't worry, it's definitely not widely known yet!) – GManNickG Feb 02 '11 at 07:21
  • @GMan But shouldn't it be possible to implement std::bind so, that it uses std::forward internally to pass rvalue if it itself got rvalue? Isn't that a bug in the std::bind implementation or in the specification (it's still draft, so reporting bugs against it makes sense, right?) – Jan Hudec Feb 02 '11 at 07:29
  • @Jan: I was surprised as well, but reading the draft it appears to simply does pass it as an lvalue. Look at §20.8.10.1.2/1, where we see the definition for `tid` (for exposition) as "is an lvalue...constructed from std::forward(ti)". The function is passed, per paragraph ten, "the value tid and its type Vi is TiD cv &". In other words, stored as a member constructed from forwarding the argument, and passed as just a vanilla value. But I can see the rationale behind this choice, and I also think forwarding the value is not needed, given other solutions I may touch on if @Tim elaborates. – GManNickG Feb 02 '11 at 07:34
  • @Tim: I see. Well I agree it's unfortunate there's no simple utility for moving the bound value, but you get no loss by binding to `foo`, which allows it. Note that you may also go a completely different route: `auto f = []{ foo(Movable()); }`. – GManNickG Feb 02 '11 at 07:48
  • @GMan Putting the rvalue ref conversion in `foo` would defeat the purpose of the `T&&` deduction. Is it possible to write my own utility function that wraps the nested bind? I just want the outer bind to look clean. Would something like this work? – Timothy003 Feb 02 '11 at 08:22
  • `template auto bind_rvalue(T &&x) -> decltype(bind(my_special_move, move(x))) { return bind(my_special_move, move(x)); }` – Timothy003 Feb 02 '11 at 08:23
  • @Timothy: You cannot bind to any template function and still have template deduction, because in order to bind you must specify the template arguments. So I'm not sure what your goal is. – GManNickG Feb 02 '11 at 08:31
  • @GMan I have other code calling `foo` normally. Changing `foo` to move `value` instead of copying it could break that code. – Timothy003 Feb 02 '11 at 08:46
  • @Timothy: I don't think I suggested changing `foo`, though I see where you got it from. But conceptually what you want is impossible, you'd be better off with a lambda. – GManNickG Feb 02 '11 at 08:57
  • @GMan Lambdas have their own problems, like not being able to capture by by rvalue reference. My `f`'s context is a bit different from the one presented; it gets the rvalue from a function argument. I'm also curious about why it's not possible to wrap the `std::bind(my_special_move, Movable())` expression into a generalized template function. (The solutions work in MSVC, but not in GCC.) Thanks for all the replies, and sorry if I seem persistent about this. I'm sure people would need this, for instance, to bind a `unique_ptr`. – Timothy003 Feb 02 '11 at 09:31
  • @Tim: Not a problem. I think it's hard to continue any further, unless we get a real concrete example, big picture and all. Then we can solve any actual problems instead of theoretical ones. – GManNickG Feb 02 '11 at 09:37
  • @GMan: your your_bind struct, however, compiles w/o errors and works perfectly, maybe it needs some corection to achive the failure :), see my answer below – user396672 Feb 02 '11 at 11:25
  • I got the solutions to work on GCC. The final code is `template T &&my_special_move(T &x) { return move(x); } template auto bind_rvalue(T &&x) -> decltype(bind((T &&(&)(T &))my_special_move, move(x))) { return bind((T &&(&)(T &))my_special_move, move(x)); }` and `auto f = bind(static_cast(foo), bind_rvalue(Movable()));`. Unfortunately, the draft says that the bind argument types require `CopyConstructible`, so binding movable-only objects isn't portable (works on GCC 4.6, but not MSVC 10). – Timothy003 Feb 02 '11 at 12:47
  • @user: You're right, because I was making a call to `foo` and not the bound `foo`. So I think your comments are in vein. :X – GManNickG Feb 02 '11 at 17:45
2

You could use a lambda expression.

auto f = [](){ foo(Movable()); };

This would seem to be the simplest option.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • Sorry I marked your answer down... Heres why: Although this would work bind is generally used for later recall of the original context... The way it was used in the original question would be the same as the closure part [...] of a lambda.. Your solution instead assumes that you CAN hold off the creation of Movable until the time you are ready to call foo. Which kind of misses the point of binding it in the first place. If you can do that why even hand the Movable object in as a parameter in the first place why not just construct it in foo directly? – Ashley Smart Nov 11 '12 at 15:14
  • 1
    He clearly states in the original question that he wants the effect of `foo(Movable())`. – Puppy Nov 11 '12 at 16:14
  • This is IMHO by far the simplest and best answer. Of course, one has to ensure, that the lambda expression is safe, especiall, if it is moves out of some value, that it captured by reference and doesn't produce a value in place. But instead of `std::bind`ing to the result of `std::bind` (as in the accepted answer), it is much easier and clearer to overlook, what happens. – Kai Petzke Apr 24 '21 at 19:26
1

Guys i have hacked up a perfect forwarding version of a binder(limited to 1 param) here http://code-slim-jim.blogspot.jp/2012/11/stdbind-not-compatable-with-stdmove.html

For reference the code is

template <typename P>
class MovableBinder1
{
  typedef void (*F)(P&&);

private:
  F func_;
  P p0_;

public:
  MovableBinder1(F func, P&& p) :
    func_(func),
    p0_(std::forward<P>(p))
  {
    std::cout << "Moved" << p0_ << "\n";
  }

  MovableBinder1(F func, P& p) :
    func_(func),
    p0_(p)
  {
    std::cout << "Copied" << p0_ << "\n";
  }

  ~MovableBinder1()
  {
    std::cout << "~MovableBinder1\n";
  }

  void operator()()
  {
    (*func_)(std::forward<P>(p0_));
  }
};

As u can see from the above proof of concept, its very possible...

I see no reason why std::bind is incompatible with std::move... std::forward is after all for perfect forwarding I dont understand why there isnt a std::forwarding_bind ???

Ashley Smart
  • 2,098
  • 2
  • 13
  • 7
  • 1
    And here is the generic solution http://code-slim-jim.blogspot.jp/2012/11/perfect-forwarding-bind-compatable-with.html – Ashley Smart Nov 13 '12 at 13:46
0

One more improvement in GManNickG's answer and I've got pretty solution:

auto f = std::bind(
    foo<Movable>,
    std::bind(std::move<Movable&>, Movable())
);

(works in gcc-4.9.2 and msvc2013)

magras
  • 1,709
  • 21
  • 32
  • 1
    You can't do this, I'm afraid, at least not as of C++20, where [nearly all stdlib functions became non-addressible](https://stackoverflow.com/questions/62251497/holding-or-passing-around-non-addressable-functions-since-c20), i.e. unable to be passed around as references or pointers. – underscore_d May 05 '23 at 19:47
  • @underscore_d, you are right. That's old rule, not from C++20. As workaround it's possible to wrap `std::move` inside a lambda, or just accept that next standard or other implementation of standard library will break this code. I'm fine with the second option in many situations. – magras May 07 '23 at 04:53
0

(This is actually a comment to GMan's answer, but I need some formatting for the code). If generated functor actually is like this:

struct your_bind
{
    your_bind(Movable arg0) :
    arg0(arg0)
    {}

    void operator()()
    {
        foo(arg0);
    }

    Movable arg0;
};

then

int main()
{
    auto f = your_bind(Movable());
    f();    // No errors!
}

compliles without errors. as it's possible to assign and initialize data with rvalue and then pass a data value to rvalue argument of the foo().
However, I suppose that bind implementation extracts function argument type directly from foo() signature. i.e. the generated functor is:

struct your_bind
{
    your_bind(Movable && arg0) :
    arg0(arg0) // ****  Error:cannot convert from Movable to Movable &&amp
    {}

    void operator()()
    {
        foo(arg0); 
    }

    Movable&& arg0;
};

and indeed, this really fails to initialize rvalue data member. Perhaps,the bind implpementation simply does not correctly extract "unreferenced" type from function argument type and uses this type for functor's data member declaration "as is", without trimming &&.

the correct functor should be:

struct your_bind
{
    your_bind(Movable&& arg0) :
    arg0(arg0)
    {}

    void operator()()
    {
        foo(arg0); 
    }

    Movable arg0; // trim && !!!
};


user396672
  • 3,106
  • 1
  • 21
  • 31