mercredi 30 décembre 2015

Why does the standard allow a tuple of rvalue references to be assigned to by a tuple of lvalue references?

It seems like a std::tuple containing one or more references has unexpected behavior with regards to construction and assignment (especially copy/move construction and copy/move assignment). It's different from the behavior of both std::reference_wrapper (changes the referred to object) and a struct with a member reference variable (assignment operator deleted). It allows for the convenient std::tie python like multiple return values, but it also allows obviously incorrect code like the following (link here):

#include <tuple>

int main()
{
    std::tuple<int&> x{std::forward_as_tuple(9)}; // OK
    std::forward_as_tuple(5) = x; // OK
    // std::get<0>(std::forward_as_tuple(5)) = std::get<0>(x); // ERROR - and should be
    return 0;
}

The standard seems to require or strongly hint at this behavior in the copy(ish) assignment section 20.4.2.2.9 of the latest working draft (Ti& will collapse to lvalue ref):

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

9 Requires: sizeof...(Types) == sizeof...(UTypes) and is_assignable<Ti&, const Ui&>::value is true for all i.

10 Effects: Assigns each element of u to the corresponding element of *this.

11 Returns: *this

Although the move(ish) construction section 20.4.2.1.20 is less clear (is_constructible<int&, int&&> returns false):

template <class... UTypes> EXPLICIT constexpr tuple(tuple<UTypes...>&& u);

18 Requires: sizeof...(Types) == sizeof...(UTypes).

19 Effects: For all i, the constructor initializes the ith element of *this with std::forward<Ui>(get<i>(u)).

20 Remarks: This constructor shall not participate in overload resolution unless is_constructible<Ti, Ui&&>::value is true for all i. The constructor is explicit if and only if is_convertible<Ui&&, Ti>::value is false for at least one i.

These are not the only affected subsections.

The question is, why is this behavior desired? Also, if there are other parts of the standard at play, or I'm misunderstanding it, explain where I went wrong.

Thanks!

Aucun commentaire:

Enregistrer un commentaire