【问题标题】:Assigning values to a tuple of references为引用元组赋值
【发布时间】:2018-02-05 10:30:59
【问题描述】:

我正在尝试设置引用元组中引用的对象的值,但无法正确解包语法。

namespace detail {

template<class... Types, std::size_t... Is>
void assign_values_helper(std::tuple<Types&...>& dest, std::index_sequence<Is...>, Types... values)
{
    std::get<Is>(dest)... = values...;
}

} // end namespace detail

template<class... Types>
void assign_values(std::tuple<Types&...>& dest, Types... values)
{
    assign_values_helper(dest, std::index_sequence_for<Types...>{}, values...);
}

我在 assign_values_helper 中收到关于 Is 未扩展的错误。

assign_values 的使用示例是

int a {};
double b {};
std::tuple<int&, double&> tup = {a, b};
assign_values(tup, 1, 2.0);

【问题讨论】:

  • 为什么不使用std::make_tuple?
  • @Holt 怎么样?注意被引用的对象不会改变,只有它们的值会改变。
  • 错误的评论编辑,std::tie 不起作用,因为它会重新分配元组,但 std::make_tuple 在这里有效。

标签: c++ tuples c++14 variadic-templates


【解决方案1】:

使用std::make_tuple:

tup = std::make_tuple(1, 2.0);

有特殊的重载operator=用于分配不同类型的std::tuple:

template <class... UTypes>
tuple& operator=(const tuple<UTypes...>& u);

template <class... UTypes>
tuple& operator=(tuple<UTypes...>&& u);

第二个(也就是在这里调用的那个)完全符合您的要求:

对于所有i,将std::forward&lt;Ui&gt;(std::get&lt;i&gt;(u)) 分配给get&lt;i&gt;(*this)。

【讨论】:

  • 是的,显然在理解了语法的好奇心之后,更倾向于标准库。 +1
  • 您还可以使用forward_as_tuple 在此和tie 之间实现两全其美。
  • @StoryTeller 怎么样?执行tup = std::forward_as_tuple(1, 2.0) 会导致存储悬空引用。
  • @Danra - 引用无法重新绑定。由于tup 持有引用,它会简单地进行成员分配(对引用的对象),并保留源的值类别。
  • @Danra - 在这种情况下它不完全匹配,因为forward_as_tuple(1, 2.0) 创建了一个右值引用的元组。即使是这样,std::tuple 的复制赋值和移动赋值运算符也可以明智地操作成员。 tup 将引用相同的对象,并将它们分配给。这一切都以一种相当理智的方式运作,即使支配整个事情的规则在阅读它们时会让人发疯。
【解决方案2】:

两个问题:

  1. 您正在尝试在 中根本不允许的上下文中展开包。

  2. 对于整个赋值表达式,应该只有一个包扩展。

我们可以通过引入一个虚拟数组来修复它,它的初始化器将为包扩展提供上下文:

int dummy[]{ ((void(std::get<Is>(dest) = values)), 0)... };
(void)dummy;

解决方案自然是折叠表达式:

(void(std::get<Is>(dest) = values), ...);

【讨论】:

  • 一如既往的感谢。呃,上下文问题的解决方法太丑陋了。看起来很奇怪,您必须如何使用折叠表达式才能使其看起来(有点)更好。
【解决方案3】:

感谢您提供一个很好的例子!

std::tie 非常适合这个:

template<class... Types>
void assign_values(std::tuple<Types&...>& dest, Types... values) {
    dest = std::tie(values...);
}

int main() {
  int a {};
  double b {};
  std::tuple<int&, double&> tup = {a, b};
  assign_values(tup, 1, 2.0);
  return a + b;
}

请参阅https://godbolt.org/g/oU2Pi8 以获取证据。

附加说明:最好添加一些 const 安全性,这也会阻止您按值传递字符串:

template<class... Types>
void assign_values(std::tuple<Types&...>& dest, const Types&... values) {
    dest = std::tie(values...);
}

【讨论】:

    猜你喜欢
    • 2011-04-23
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多