【发布时间】:2016-04-05 05:04:43
【问题描述】:
似乎包含一个或多个引用的std::tuple 在构造和分配(尤其是复制/移动构造和复制/移动分配)方面具有意外行为。它不同于std::reference_wrapper(更改引用的对象)和具有成员引用变量的结构(删除了赋值运算符)的行为。它允许方便的std::tie python 像多个返回值,但它也允许明显不正确的代码,如以下(link here):
#include <tuple>
int main()
{
std::tuple<int&> x{std::forward_as_tuple(9)}; // OK - doesn't seem like it should be
std::forward_as_tuple(5) = x; // OK - doesn't seem like it should be
// std::get<0>(std::forward_as_tuple(5)) = std::get<0>(x); // ERROR - and should be
return 0;
}
该标准似乎在最新工作草案的复制(ish)分配部分20.4.2.2.9 中要求或强烈暗示此行为(Ti& 将折叠为左值参考):
template <class... UTypes> tuple& operator=(const tuple<UTypes...>& u);9 要求:
sizeof...(Types) == sizeof...(UTypes)和is_assignable<Ti&, const Ui&>::value对所有i都是 true。10 作用:将u的每个元素赋值给*this的对应元素。
11 返回: *this
虽然移动(ish)构造部分 20.4.2.1.20 不太清楚(is_constructible<int&, int&&> 返回 false):
template <class... UTypes> EXPLICIT constexpr tuple(tuple<UTypes...>&& u);18 要求:
sizeof...(Types) == sizeof...(UTypes)。19 作用:对于所有
i,构造函数将*this的ith元素初始化为std::forward<Ui>(get<i>(u))。20 备注:除非
is_constructible<Ti, Ui&&>::value对所有i都为真,否则此构造函数不应参与重载决议。当且仅当is_convertible<Ui&&, Ti>::value对于至少一个i为假时,构造函数为explicit。
这些不是唯一受影响的小节。
问题是,为什么需要这种行为?另外,如果该标准的其他部分在起作用,或者我有误解,请解释我哪里出错了。
谢谢!
【问题讨论】:
-
对此进行了更多研究。似乎包含右值引用的
std::tuple不应该支持赋值(尽管标准没有提到这一点),并且来自std::tuple<RVALUEREF>的std::tuple<LVALUEREF>构造可能是libc++ 中的一个错误。任何输入都是有价值的,因为我正在实现一个元组变体。 -
libc++ 是正确的,并且已经有一段时间了。请参阅霍华德的回答。
标签: c++ c++11 assignment-operator stdtuple