std::bind and/or std::forward 的语义

Semantics of std::bind and/or std::forward

下面的代码编译失败,我觉得很迷惑

#include <functional>

class Mountain {
public:
  Mountain() {}
  Mountain(const Mountain&) = delete;
  Mountain(Mountain&&) = delete;
  ~Mountain() {}
};

int main () {
  Mountain everest;
  // shouldn't the follwing rvalues be semantically equivalent?
  int i = ([](const Mountain& c) { return 1; })(everest);
  int j = (std::bind([](const Mountain& c) {return 1;},everest))();
  return 0;
}

编译错误为:

$ g++ -std=c++20 test.cpp -o test
In file included from test.cpp:1:
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:486:26: error: no
      matching constructor for initialization of 'tuple<Mountain>'
        : _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...)
                                ^             ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/functional:788:14: note: in
      instantiation of function template specialization 'std::_Bind<(lambda at test.cpp:14:22)
      (Mountain)>::_Bind<Mountain &>' requested here
      return typename __helper_type::type(std::forward<_Func>(__f),
             ^
test.cpp:14:17: note: in instantiation of function template specialization 'std::bind<(lambda at
      test.cpp:14:22), Mountain &>' requested here
  int j = (std::bind([](const Mountain& c) {return 1;}, everest))();
                ^
...

所以 std::bind 偷偷地尝试复制 everest 即使 lambda 只需要对它的引用。我是否遇到了一个没人关心的奇怪的边缘情况(例如,总是可以只使用 lambda 捕获对 everest 的引用)或者是否有理由?如果理由是 bind 在 everest 被销毁后保护我不调用 lambda,是否有一个不安全的 bind 版本不会那样做?

是的,std::bind 的参数将被复制(或移动)。

The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.

您可以改用 std::cref(或 std::ref)。例如

int j = (std::bind([](const Mountain& c) {return 1;}, std::cref(everest)))();
//                                                    ^^^^^^^^^^       ^

LIVE