【问题标题】:std::bind and rvalue referencestd::bind 和右值引用
【发布时间】:2016-04-24 23:31:13
【问题描述】:

让我们考虑以下代码:

class Widget{
};

int main(){
Widget w;
auto lambda = bind([](Widget&& ref){ return; }, std::move(w));

return 0;
}

它会触发错误

no match for call to ‘(std::_Bind<main()::<lambda(Widget&&)>(Widget)>) ()’
     lambda();

我的问题是:为什么会出现错误?毕竟,我对右值引用进行了显式转换——我的意思是std::move(w),我通过右值引用进行论证——我的意思是Widget&amp;&amp; ref

怎么了?

此外,下面的代码有效,让我更担心的是:

class Widget{
};

int main(){
Widget w;
auto lambda = bind([](Widget& ref){ return; }, std::move(w));

return 0;
}

【问题讨论】:

    标签: c++ c++11 rvalue-reference


    【解决方案1】:

    如果你把std::bind 的作用写下来可能会更清楚。

    // C++14, you'll have to write a lot of boilerplate code for C++11
    template <typename FuncT, typename ArgT>
    auto
    bind(FuncT&& func, ArgT&& arg)
    {
      return
        [
          f = std::forward<FuncT>(func),
          a = std::forward<ArgT>(arg)
        ]() mutable { return f(a); };  // NB: a is an lvalue here
    }
    

    由于您可以多次调用函数对象std::bind 给您,它不能“用完”捕获的参数,因此它将作为左值引用传递。您将 bind 本身传递为右值这一事实仅意味着在初始化 a 的行上没有复制。

    如果您尝试使用上面显示的示意图 bind 编译您的示例,您还会从编译器中获得更有用的错误消息。

    main.cxx: In instantiation of ‘bind(FuncT&&, ArgT&&)::<lambda()> mutable [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’:
    main.cxx:10:33:   required from ‘struct bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]::<lambda()>’
    main.cxx:11:31:   required from ‘auto bind(FuncT&&, ArgT&&) [with FuncT = main()::<lambda(Widget&&)>; ArgT = Widget]’
    main.cxx:18:59:   required from here
    main.cxx:11:26: error: no match for call to ‘(main()::<lambda(Widget&&)>) (Widget&)’
        ]() mutable { return f(a); };  // NB: a is an lvalue here
                              ^
    main.cxx:11:26: note: candidate: void (*)(Widget&&) <conversion>
    main.cxx:11:26: note:   conversion of argument 2 would be ill-formed:
    main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
    main.cxx:18:33: note: candidate: main()::<lambda(Widget&&)> <near match>
       auto lambda = bind([](Widget&&){ return; }, std::move(w));
                                     ^
    main.cxx:18:33: note:   conversion of argument 1 would be ill-formed:
    main.cxx:11:26: error: cannot bind ‘Widget’ lvalue to ‘Widget&&’
        ]() mutable { return f(a); };  // NB: a is an lvalue here
    

    【讨论】:

      【解决方案2】:

      要让它工作,你需要这样写:

      #include <functional>
      #include <iostream>
      
      class Widget{};
      
      int main()
      {
          Widget a;
          auto lf = [](Widget&& par){ };
      
          auto f = std::bind
          (
              lf,
              std::bind
              (
                  std::move<Widget&>, a
              )
          );
          f();
          return 0;
      }
      

      我的编译器是gcc version 4.9.2 20141101 (Red Hat 4.9.2-1) (GCC)

      【讨论】:

      • 你是怎么发现这个例子行不通的?我用我的编译器成功编译了它。你用什么编译器?
      • 对不起,我对我的程序的命名感到困惑,GCC 没有告诉我有两个函数可以调用。
      猜你喜欢
      • 2015-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 2023-03-16
      • 2014-12-17
      • 1970-01-01
      相关资源
      最近更新 更多