This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of Resolved status.
Section: 22.3.2 [pairs.pair], 22.4.4.2 [tuple.cnstr] Status: Resolved Submitter: Daniel Krügler Opened: 2010-03-07 Last modified: 2016-01-28
There are several constructors and creation functions of std::tuple that impose requirements on it's arguments, that are unnecessary restrictive and don't match the intention for the supported argument types. This is related to the fact that tuple is supposed to accept both object types and lvalue-references and the usual MoveConstructible and CopyConstructible requirements are bad descriptions for non-const references. Some examples:
22.4.4.2 [tuple.cnstr] before p.4 and p.8, resp.:
explicit tuple(const Types&...);4 Requires: Each type in
Types
shall be copy constructible.tuple(const tuple& u) = default;8 Requires: Each type in
Types
shall satisfy the requirements ofCopyConstructible
(Table 34).
A tuple that contains lvalue-references to non-const can never satisfy the CopyConstructible
requirements. CopyConstructible
requirements refine the MoveConstructible
requirements and this would require that these lvalue-references could bind rvalues. But the core language does not allow that. Even, if we would interpret that requirement as referring to the underlying non-reference type, this requirement would be wrong as well, because there is no reason to disallow a type such as
struct NoMoveNoCopy { NoMoveNoCopy(NoMoveNoCopy&&) = delete; NoMoveNoCopy(const NoMoveNoCopy&) = delete; ... }:
for the instantiation of std::tuple<NoMoveNoCopy&>
and that of it's copy constructor.
A more reasonable requirement for this example would be to require that "is_constructible<Ti, const Ti&>::value
shall evaluate to true for all Ti
in Types
". In this case the special reference-folding and const-merging rules of references would make this well-formed in all cases. We could also add the further constraint "if Ti
is an object type, it shall satisfy the CopyConstructible
requirements", but this additional requirement seems not really to help here. Ignoring it would only mean that if a user would provide a curious object type C
that satisfies the std::is_constructible<C, const C&>
test, but not the "C
is CopyConstructible
" test would produce a tuple<C>
that does not satisfy the CopyConstructible
requirements as well.
22.4.4.2 [tuple.cnstr] before p.6 and p.10, resp.:
template <class... UTypes> explicit tuple(UTypes&&... u);6 Requires: Each type in
Types
shall satisfy the requirements ofMoveConstructible
(Table 33) from the corresponding type inUTypes
.sizeof...(Types) == sizeof...(UTypes)
.tuple(tuple&& u);10 Requires: Each
type
inTypes
shall shall satisfy the requirements ofMoveConstructible
(Table 33).
We have a similar problem as in (a): Non-const lvalue-references are intended template arguments for std::tuple
, but cannot satisfy the MoveConstructible
requirements. In this case the correct requirements would be
is_constructible<Ti, Ui>::value
shall evaluate to true for allTi
inTypes
and for allUi
inUTypes
and
is_constructible<Ti, Ti>::value
shall evaluate to true for allTi
inTypes
respectively.
Many std::pair
member functions do not add proper requirements, e.g. the default c'tor does not require anything. This is corrected within the suggested resolution. Further-on the P/R has been adapted to the FCD numbering.
Change 22.3.2 [pairs.pair]/1 as indicated [The changes for the effects elements are not normative changes, they just ensure harmonization with existing wording style]:
constexpr pair();Requires:
first_type
andsecond_type
shall satisfy theDefaultConstructible
requirements.1 Effects: Value-initializes
first
andsecond
. Initializes its members as if implemented:pair() : first(), second() { }
.
Change 22.3.2 [pairs.pair]/2 as indicated:
pair(const T1& x, const T2& y);Requires:
is_constructible<T1, const T1&>::value
istrue
andis_constructible<T2, const T2&>::value
istrue
.2 Effects: The constructor initializes
first
withx
andsecond
withy
.
Change 22.3.2 [pairs.pair]/3 as indicated:
template<class U, class V> pair(U&& x, V&& y);Requires:
is_constructible<first_type, U>::value
istrue
andis_constructible<second_type, V>::value
istrue
.3 Effects: The constructor initializes
first
withstd::forward<U>(x)
andsecond
withstd::forward<V>(y)
.4 Remarks: If
U
is not implicitly convertible tofirst_type
orV
is not implicitly convertible tosecond_type
this constructor shall not participate in overload resolution.
Change 22.3.2 [pairs.pair]/5 as indicated [The change in the effects element should be non-normatively and is in compatible to the change suggestion of 1324(i)]:
template<class U, class V> pair(const pair<U, V>& p);Requires:
is_constructible<first_type, const U&>::value
istrue
andis_constructible<second_type, const V&>::value
istrue
.5 Effects: Initializes members from the corresponding members of the argument , performing implicit conversions as needed.
Change 22.3.2 [pairs.pair]/6 as indicated:
template<class U, class V> pair(pair<U, V>&& p);Requires:
is_constructible<first_type, U>::value
istrue
andis_constructible<second_type, V>::value
istrue
.6 Effects: The constructor initializes
first
withstd:: move forward<U>(p.first)
andsecond
withstd:: move forward<V>(p.second)
.
Change 22.3.2 [pairs.pair]/7+8 as indicated [The deletion in the effects element should be non-normatively]:
template<class... Args1, class... Args2> pair(piecewise_construct_t, tuple<Args1...> first_args, tuple<Args2...> second_args);7 Requires:
is_constructible<first_type, Args1...>::value
istrue
andis_constructible<second_type, Args2...>::value
istrue
. All the types inArgs1
andArgs2
shall beCopyConstructible
(Table 35).T1
shall be constructible fromArgs1
.T2
shall be constructible fromArgs2
.8 Effects: The constructor initializes
first
with arguments of typesArgs1...
obtained by forwarding the elements offirst_args
and initializessecond
with arguments of typesArgs2...
obtained by forwarding the elements ofsecond_args
. (Here, forwarding an elementx
of typeU
within atuple
object means callingstd::forward<U>(x)
.) This form of construction, whereby constructor arguments forfirst
andsecond
are each provided in a separatetuple
object, is called piecewise construction.
Change 22.3.2 [pairs.pair] before 12 as indicated:
pair& operator=(pair&& p);Requires:
first_type
andsecond_type
shall satisfy theMoveAssignable
requirements.12 Effects: Assigns to
first
withstd::move(p.first)
and tosecond
withstd::move(p.second)
.13 Returns:
*this
.
Change [pairs.pair] before 14 as indicated: [The heterogeneous usage of MoveAssignable is actually not defined, but the library uses it at several places, so we follow this tradition until a better term has been agreed on. One alternative could be to write "first_type shall be assignable from an rvalue of U [..]"]
template<class U, class V> pair& operator=(pair<U, V>&& p);Requires:
first_type
shall beMoveAssignable
fromU
andsecond_type
shall beMoveAssignable
fromV
.14 Effects: Assigns to
first
withstd::move(p.first)
and tosecond
withstd::move(p.second)
.15 Returns:
*this
.
Change 22.4.4.2 [tuple.cnstr]/4+5 as indicated:
explicit tuple(const Types&...);4 Requires:
is_constructible<Ti, const Ti&>::value == true
for e Each typeTi
inTypes
shall be copy constructible.5 Effects: Copy i Initializes each element with the value of the corresponding parameter.
Change 22.4.4.2 [tuple.cnstr]/6 as indicated:
template <class... UTypes> explicit tuple(UTypes&&... u);6 Requires:
is_constructible<Ti, Ui>::value == true
for e Each typeTi
inTypes
shall satisfy the requirements ofMoveConstructible
(Table 33) from and for the corresponding typeUi
inUTypes
.sizeof...(Types) == sizeof...(UTypes)
.7 Effects: Initializes the elements in the
tuple
with the corresponding value instd::forward<UTypes>(u)
.
Change 22.4.4.2 [tuple.cnstr]/8+9 as indicated:
tuple(const tuple& u) = default;8 Requires:
is_constructible<Ti, const Ti&>::value == true
for e Each typeTi
inTypes
shall satisfy the requirements ofCopyConstructible
(Table 34).9 Effects: Initializes Copy constructs each element of
*this
with the corresponding element ofu
.
Change 22.4.4.2 [tuple.cnstr]/10+11 as indicated:
tuple(tuple&& u);10 Requires: Let
i
be in[0, sizeof...(Types))
and letTi
be thei
th type inTypes
. Thenis_constructible<Ti, Ti>::value
shall betrue
for alli
. Each type inTypes
shall shall satisfy the requirements ofMoveConstructible
(Table 34).11 Effects: For each
Ti
inTypes
, initializes thei
th Move-constructs each element of*this
with the corresponding element ofstd::forward<Ti>(get<i>(
u
))
.
Change 22.4.4.2 [tuple.cnstr]/15+16 as indicated:
template <class... UTypes> tuple(tuple<UTypes...>&& u);15 Requires: Let
i
be in[0, sizeof...(Types))
,Ti
be thei
th type inTypes
, andUi
be thei
th type inUTypes
. Thenis_constructible<Ti, Ui>::value
shall betrue
for alli
. Each type inTypes
shall shall satisfy the requirements ofMoveConstructible
(Table 34) from the corresponding type inUTypes
.sizeof...(Types) == sizeof...(UTypes)
.16 Effects: For each type
Ti
, initializes thei
th Move-constructs each element of*this
with the corresponding element ofstd::forward<Ui>(get<i>(
u
))
.
Change 22.4.4.2 [tuple.cnstr]/19+20 as indicated:
template <class U1, class U2> tuple(pair<U1, U2>&& u);19 Requires:
is_constructible<T1, U1>::value == true
fort
T
he first typeT1
inTypes
shall shall satisfy the requirements ofMoveConstructible
(Table 33) fromU1
andis_constructible<T2, U2>::value == true
for the second typeT2
inTypes
shall be move-constructible fromU2
.sizeof...(Types) == 2
.20 Effects: Initializes Constructs the first element with
std:: forward<U1> move(u.first)
and the second element withstd:: forward<U2> move(u.second)
.
Change 22.4.5 [tuple.creation]/9-16 as indicated:
template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(const tuple<TTypes...>& t, const tuple<UTypes...>& u);9 Requires:
is_constructible<Ti, const Ti&>::value == true
for each typeTi
All the types inTTypes
shall beCopyConstructible
(Table 34).is_constructible<Ui, const Ui&>::value == true
for each typeUi
All the types inUTypes
shall beCopyConstructible
(Table 34).10 Returns: A
tuple
object constructed by initializing copy constructing its firstsizeof...(TTypes)
elements from the corresponding elements oft
and initializing copy constructing its lastsizeof...(UTypes)
elements from the corresponding elements ofu
.template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(tuple<TTypes...>&& t, const tuple<UTypes...>& u);11 Requires: Let
i
be in[0, sizeof...(TTypes))
,Ti
be thei
th type inTypes
,j
be in[0, sizeof...(UTypes))
, andUj
be thej
th type inUTypes
.is_constructible<Ti, Ti>::value
shall betrue
for each typeTi
andis_constructible<Uj, const Uj&>::value
shall betrue
for each typeUj
All the types inTTypes
shall beMoveConstructible
(Table 34). All the types inUTypes
shall beCopyConstructible
(Table 35).12 Returns: A
tuple
object constructed by initializing thei
th element withstd::forward<Ti>(get<i>(t))
for allTi
inTTypes
and initializing the(j+sizeof...(TTypes))
th element withget<j>(u)
for allUj
inUTypes
. move constructing its firstsizeof...(TTypes)
elements from the corresponding elements oft
and copy constructing its lastsizeof...(UTypes)
elements from the corresponding elements ofu
.template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(const tuple<TTypes...>& t, tuple<UTypes...>&& u);13 Requires: Let
i
be in[0, sizeof...(TTypes))
,Ti
be thei
th type inTypes
,j
be in[0, sizeof...(UTypes))
, andUj
be thej
th type inUTypes
.is_constructible<Ti, const Ti&>::value
shall betrue
for each typeTi
andis_constructible<Uj, Uj>::value
shall betrue
for each typeUj
All the types inTTypes
shall beCopyConstructible
(Table 35). All the types inUTypes
shall beMoveConstructible
(Table 34).14 Returns: A
tuple
object constructed by initializing thei
th element withget<i>(t)
for each typeTi
and initializing the(j+sizeof...(TTypes))
th element withstd::forward<Uj>(get<j>(u))
for each typeUj
copy constructing its firstsizeof...(TTypes)
elements from the corresponding elements oft
and move constructing its lastsizeof...(UTypes)
elements from the corresponding elements ofu
.template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(tuple<TTypes...>&& t, tuple<UTypes...>&& u);15 Requires: Let
i
be in[0, sizeof...(TTypes))
,Ti
be thei
th type inTypes
,j
be in[0, sizeof...(UTypes))
, andUj
be thej
th type inUTypes
.is_constructible<Ti, Ti>::value
shall betrue
for each typeTi
andis_constructible<Uj, Uj>::value
shall betrue
for each typeUj
All the types inTTypes
shall beMoveConstructible
(Table 34). All the types inUTypes
shall beMoveConstructible
(Table 34).16 Returns: A
tuple
object constructed by initializing thei
th element withstd::forward<Ti>(get<i>(t))
for each typeTi
and initializing the(j+sizeof...(TTypes))
th element withstd::forward<Uj>(get<j>(u))
for each typeUj
move constructing its firstsizeof...(TTypes)
elements from the corresponding elements oft
and move constructing its lastsizeof...(UTypes)
elements from the corresponding elements ofu
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4