Reputation: 165
// TEMPLATE CONSTRUCTOR pair::pair(tuple, tuple, sequence, sequence)
template<class _Ty1,
class _Ty2>
template<class _Tuple1,
class _Tuple2,
size_t... _Indexes1,
size_t... _Indexes2> inline
pair<_Ty1, _Ty2>::pair(_Tuple1& _Val1,
_Tuple2& _Val2,
index_sequence<_Indexes1...>,
index_sequence<_Indexes2...>)
: first(_STD get<_Indexes1>(_STD move(_Val1))...),
second(_STD get<_Indexes2>(_STD move(_Val2))...)
{ // construct from pair of tuples
}
// TEMPLATE CONSTRUCTOR pair::pair(piecewise_construct_t, tuple, tuple)
template<class _Ty1,
class _Ty2>
template<class... _Types1,
class... _Types2> inline
pair<_Ty1, _Ty2>::pair(piecewise_construct_t,
tuple<_Types1...> _Val1,
tuple<_Types2...> _Val2)
: pair(_Val1, _Val2,
index_sequence_for<_Types1...>(),
index_sequence_for<_Types2...>())
{ // construct from pair of tuples
}
The above is the source code of tuple in VisualStudio. It is the piece-wise constructor of std::pair. The second constructor calls the first one. In the first constructor, data member first and second are initialized by
first(_STD get<_Indexes1>(_STD move(_Val1))...), second(_STD get<_Indexes2>(_STD move(_Val2))...)
I don't understand why std::move can be used here. What if some arguments in the tuple is not an rvalue? Wouldn't it make arguments that are lvalues to become rvalues and invoke unintended constructor of first and second?
Upvotes: 0
Views: 124
Reputation: 13269
The first constructor is not part of the interface. It's only called for delegation by the second one, where _Val1
and _Val2
are passed by value, so the first constructor can move them.
Because of the std::move
call, the overloads of std::get
that can get called here are:
template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type&&
get( tuple<Types...>&& t ) noexcept;
template< std::size_t I, class... Types >
typename std::tuple_element<I, tuple<Types...> >::type const&&
get( const tuple<Types...>&& t ) noexcept;
In both cases, if typename std::tuple_element<I, tuple<Types...> >::type
is an lvalue reference, the return type stays an lvalue reference because T& &&
is just T&
. So no move can occur on lvalue reference elements of the tuple.
Upvotes: 1