1

I have to store arguments (parameter pack), and pass the arguments to another function.
As a result, I cannot use lambda. And a good choice is std::bind.

But for this code

struct A{};

void test(A &&){}

int main()
{
    A a;
    test(move(a));    //work
    bind(test,a)();   //compile fail; copy a to std::bind, pass a to test
}

According to standard, all variables stored in std::bind will be pass as lvalue to function. (The C++ standard doesn't say that, by I think that is what it means.)
And that means I cannot use a function (has rvalue reference in parameter) with std::bind.

One solution is to change test(A &&) to test(A &), but this only works for your project (and make it strange while you not only need to call test by std::thread but also need to call test by plain sequential call).

So, is there any ways to solve this problem?

Caesar
  • 971
  • 6
  • 13
  • 5
    *"I cannot use lambda"*, can you elaborate on that? and where is the parameter pack you mention ? – Piotr Skotnicki Jul 06 '16 at 15:48
  • @NathanOliver you forgot to call `foo` – Piotr Skotnicki Jul 06 '16 at 15:48
  • @PiotrSkotnicki Good point. I did that and it fails spectacularly. – NathanOliver Jul 06 '16 at 15:51
  • @PiotrSkotnicki, because I have to pass the arguments from this thread to another running (but suspended) thread. There is no way to store parameter pack in capture list. If I store parameter pack inside lambda (not capture list), to make it fast, I must capture by reference, but this makes another problem. – Caesar Jul 06 '16 at 16:00
  • "*There is no way to store parameter pack in capture list.*", there is, in a tuple – Piotr Skotnicki Jul 06 '16 at 16:07
  • @PiotrSkotnicki, I am not familiar with tuple, but I will give it a shot, thank you for your keyword. – Caesar Jul 06 '16 at 16:09

1 Answers1

2

You can create wrapper which will be convertible to the rvalue reference (like reference_wrapper/l-value references) and use it with bind:

It cal look like that:

#include <iostream>
#include <functional>

struct A{};

void test(A &&){ std::cout << "Works!\n"; }

template <typename T>
struct rvalue_holder
{
    T value;
    explicit rvalue_holder(T&& arg): value(arg) {}
    operator T&&()
    {
        return std::move(value);
    }
};

template <typename T>
rvalue_holder<T> rval(T && val)
{
    return rvalue_holder<T>(std::move(val));
}

int main()
{
    A a;
    test(std::move(a));    //work
    auto foo = std::bind(test, rval(std::move(a)));   //works
    foo();
}

http://coliru.stacked-crooked.com/a/56220bc89a32c860

Note: both rvalue_holder and especially rval need further work to ensure efficiency, robustness and desired behavior in all cases.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48