【问题标题】:Evaluation order with std::tie() and assignment使用 std::tie() 和赋值的评估顺序
【发布时间】:2021-03-23 18:50:51
【问题描述】:

以下内容有效吗?

template <typename T>
std::pair<T, T> foo(T one, T two) { ... }

std::tie(one, two) = foo(std::move(one), std::move(two));

(假设所涉及的类以有效的方式处理分配给移动对象)。


通过阅读更新后的evaluation order proposal,我的假设是这个问题已经修复,但我在标准中找不到可以验证这一点的准确参考。有人可以帮忙提供吗?

【问题讨论】:

  • 你可能想选择一个不同的函数名,以便一目了然这与std::transform无关
  • @Brian 好点,更新了问题。
  • LHS 和 RHS 评估都是在分配之前排序的,所以不应该有任何东西。
  • 建议更改的链接很吸引人,谢谢。有任何迹象表明它曾被接受?
  • @MarkRansom 我找不到接受的 C++17 提案列表,但第 14-21 点看起来与此处的链接提案有关 en.cppreference.com/w/cpp/language/eval_order

标签: c++ c++17 language-lawyer


【解决方案1】:

标准中的相关部分可以在[expr.ass]/1中找到,它有

在所有情况下,赋值顺序在左右操作数的值计算之后,赋值表达式的值计算之前。右操作数在左操作数之前排序。对于一个不确定顺序的函数调用,复合赋值的操作是一个单一的求值。

因此,根据这个,foo(std::move(one), std::move(two)); 将首先被评估,一旦std::tie(one, two) 被评估,onetwo 就会从对象中移动。 tie 创建引用,因此无法访问从那里移动的对象。然后分配实际上发生意味着onetwo 通过std::tuple::operator = 分配并获得foo 返回的任何值。这是合法且定义明确的。

【讨论】:

    【解决方案2】:

    无论 C++17 对 = 的评估顺序有何更改,代码都是有效的。

    由于 LHS 不从 onetwo 读取,而只是获取它们的地址,因此相对于 RHS 未排序(C++17 之前)不会导致 UB。

    【讨论】:

      猜你喜欢
      • 2012-02-02
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-10
      • 2015-04-07
      相关资源
      最近更新 更多