Похоже, что std::tuple
, содержащий одну или несколько ссылок, имеет неожиданное поведение в отношении построения и назначения (особенно построения копирования/перемещения и назначения копирования/перемещения). Это отличается от поведения как std::reference_wrapper
(изменяет объект, на который делается ссылка), так и структуры с переменной-ссылкой на элемент (оператор присваивания удален). Это позволяет использовать удобный std::tie
python, такой как несколько возвращаемых значений, но также допускает явно неправильный код, например следующий заголовок (ссылка здесь):
#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;
}
Стандарт, по-видимому, требует или сильно намекает на такое поведение в разделе назначения копирования (иш) 20.4.2.2.9
последнего рабочего проекта (Ti&
свернется до lvalue ref):
template <class... UTypes> tuple& operator=(const tuple<UTypes...>& u);
9 Требуется:
sizeof...(Types) == sizeof...(UTypes)
иis_assignable<Ti&, const Ui&>::value
верно для всехi
.10 Эффекты: присваивает каждому элементу u соответствующий элемент *this.
11 Возвраты: *this
Хотя секция построения move(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
конструктор инициализируетi
th элемент*this
значениемstd::forward<Ui>(get<i>(u))
.20 Примечания. Этот конструктор не должен участвовать в разрешении перегрузки, если
is_constructible<Ti, Ui&&>::value
не истинно для всехi
. Конструктор являетсяexplicit
тогда и только тогда, когдаis_convertible<Ui&&, Ti>::value
ложно хотя бы для одногоi
.
Это не единственные затронутые подразделы.
Вопрос в том, почему такое поведение желательно? Кроме того, если есть другие части стандарта, или я неправильно их понимаю, объясните, где я ошибся.
Спасибо!
std::tuple
, содержащий ссылки на rvalue, не должен поддерживать присваивание (хотя в стандарте это не упоминается), а конструкцияstd::tuple<LVALUEREF>
изstd::tuple<RVALUEREF>
может быть ошибкой в libc++. Любой вклад будет ценным, так как я реализую вариант кортежа. - person xcvr   schedule 02.01.2016