C++ - std::绑定调用运算符()与完美的转发

C++ - std::bind call operator() with perfect forwarding

本文关键字:完美 转发 运算符 std 绑定 调用 C++      更新时间:2023-10-16

我必须存储参数(参数包),并将参数传递给另一个函数。
因此,我无法使用lambda。一个不错的选择是 std::bind。

但是对于此代码

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
}

根据标准,存储在 std::bind 中的所有变量都将作为左值传递给函数。(C++标准没有这么说,我认为这就是它的意思。
这意味着我不能将函数(参数中有右值引用)与 std::bind 一起使用。

一种解决方案是将test(A &&)更改为test(A &),但这仅适用于您的项目(并且当您不仅需要通过 std::thread 调用 test 而且还需要通过普通顺序调用调用 test 时,这很奇怪)。

那么,有没有办法解决这个问题呢?

您可以创建可转换为右值引用(如 reference_wrapper/l 值引用)的包装器,并将其与 bind 一起使用:

它看起来像这样:

#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

注意:rvalue_holder,尤其是rval都需要进一步的工作,以确保在所有情况下的效率、稳健性和所需的行为。