【问题标题】:Mistake with bind in "The C++ Programming Language [4th Edition] - Bjarne Stroustrup"“C++ 编程语言 [第 4 版] - Bjarne Stroustrup”中的绑定错误
【发布时间】:2018-01-23 17:01:36
【问题描述】:

我在 Bjarne Stroustrup 的书中找到了这段代码:

这段代码的问题是变量i没有停留在2,而是递增到3。你可以在这里查看:https://wandbox.org/permlink/p5JC1nOA4pIpsgXb

我们不必使用std::ref() 来增加这个变量。这是书中的错误还是自 C++11 以来发生了一些变化?

【问题讨论】:

  • 天哪,这字体太可怕了..
  • 您检查过勘误表吗? stroustrup.com/4th_printing3.html
  • @RichardCritten 似乎没有提到std::bind
  • 天哪,这不是字体——我看起来都像 l。排版混乱?
  • 链接页面不包含任何代码。

标签: c++ c++11 bind


【解决方案1】:

该示例不正确,bind 确实会复制其参数,除非您将其包装在 std::reference_wrapper 中,正如文本正确说明的那样,但这不是示例显示的内容。在示例中,参数i 被传递给bind 返回的函子,而不是bind 本身。如果示例如下所示,i 的值将保持为2

auto inc = bind(incr, i);   // a copy of i is made
inc(); // i stays 2; inc(i) incremented a local copy of i

在本书所示的示例中,参数i 将被转发到incr,这将导致对原始i 的左值引用被传递给函数,而原始i 将递增。

对于相关标准报价,来自23.14.11.3 [func.bind.bind]/10

绑定参数v1v2、...、vN 及其对应类型V1V2、...、VN 的值取决于从调用派生的TDi 类型到 bind 和调用包装器 g 的 cv 限定符 cv 如下:
...
— 如果is_­placeholder_­v<TDi> 的值j 不为零,则参数为std​::​forward<Uj>(uj),其类型ViUj&&

【讨论】:

  • 我删除了我的答案,因为我认为你是对的,所以让我把这个问题移到这里:bind 创建的仿函数应该有函数:void operator() (int&& arg) const { incr(arg); } 所以传递一个本地的@987654351 @ 到期望 int&& 的函数应该具有通过引用传递的效果?
  • @JonathanMee 不,如果那是签名 inc(i) 将无法编译,因为您将尝试将左值绑定到右值引用。签名是template <typename T> void operator(T&& arg) { incr(std::forward<T>(arg)); }。因此,该示例将对原始i 的引用转发到incr
  • 所以当将i 传递给接受int&& 的函数时,arg 实际上将是int&?也就是说arg转发给incr的时候,转发的是int&
  • @JonathanMee _N 占位符做完美转发,这意味着原始参数的值类别被保留。如果 incr 被定义为 void incr(int&&) 并且您尝试调用 inc(i) 它不会编译,因为您将尝试将左值绑定到右值引用参数。在这种情况下,您必须写 inc(std::move(i))
  • 我看不出我在哪里说过需要int&&。如果您指的是template <typename T> void operator()(T&&) 中的T&&,那么这就是forwarding reference,以前称为通用引用。当你将i(一个左值)传递给它时,T 将被推导出为int&,发生引用折叠并且参数类型为int&
猜你喜欢
  • 1970-01-01
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
  • 2018-12-25
  • 1970-01-01
相关资源
最近更新 更多