This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 20.4 [mem.composite.types] Status: New Submitter: Jonathan B. Coe Opened: 2025-08-20 Last modified: 2025-08-28
Priority: Not Prioritized
View all issues with New status.
Discussion:
The class templates indirect<T>
and polymorphic<T>
allow the template argument T
to be an incomplete type.
T
is incomplete: constraints are written so that requirements
on incomplete types are not evaluated at class instantiation time.
For constructors with additional template parameters, there are currently constraints written on the potentially
incomplete type T
and the additional template parameters. Such constraints will not be evaluated at class
instantiation time but could be explicitly evaluated in contexts where support for an incomplete T
is required.
template<typename U> class A { U u; public: A(const SomeType&) requires std::is_constructible_v<U, SomeType> { // […] } };
when U
is indirect<T>
or polymorphic<T>
for some type T
, the existence
of the requires clause will require that T
is a complete type for constraints on indirect or polymorphic
to be evaluated.
T
should be converted to Mandates on T
so that constraint evaluation
does not require T
to be a complete type.
Proposed resolution:
This wording is relative to N5014.
Modify 20.4.1.3 [indirect.ctor] as indicated:
template<class U = T> constexpr explicit indirect(U&& u);-17- Constraints:
(17.1) —
is_same_v<remove_cvref_t<U>, indirect>
isfalse
,(17.2) —
is_same_v<remove_cvref_t<U>, in_place_t>
isfalse
, and
(17.3) —is_constructible_v<T, U>
istrue
, and(17.4) —
is_default_constructible_v<Allocator>
istrue
.-?- Mandates:
-18- Effects: […]is_constructible_v<T, U>
istrue
.template<class U = T> constexpr explicit indirect(allocator_arg_t, const Allocator& a, U&& u);-19- Constraints:
(19.1) —
is_same_v<remove_cvref_t<U>, indirect>
isfalse
, and(19.2) —
is_same_v<remove_cvref_t<U>, in_place_t>
isfalse
., and
(19.3) —is_constructible_v<T, U>
istrue
-?- Mandates:
-20- Effects: […]is_constructible_v<T, U>
istrue
.template<class... Us> constexpr explicit indirect(in_place_t, Us&&... us);-21- Constraints:
(21.1) —is_constructible_v<T, Us...>
istrue
, and
(21.2) —is_default_constructible_v<Allocator>
istrue
.-?- Mandates:
-22- Effects: […]is_constructible_v<T, Us...>
istrue
.template<class... Us> constexpr explicit indirect(allocator_arg_t, const Allocator& a, in_place_t, Us&& ...us);-23-
-24- Effects: […]ConstraintsMandates:is_constructible_v<T, Us...>
istrue
template<class I, class... Us> constexpr explicit indirect(in_place_t, initializer_list<I> ilist, Us&&... us);-25- Constraints:
(25.1) —is_constructible_v<T, initializer_list<I>&, Us...>
istrue
, and
(25.2) —is_default_constructible_v<Allocator>
istrue
.-?- Mandates:
-26- Effects: […]is_constructible_v<T, initializer_list<I>&, Us...>
istrue
.template<class I, class... Us> constexpr explicit indirect(allocator_arg_t, const Allocator& a, in_place_t, initializer_list<I> ilist, Us&&... us);-27-
-28- Effects: […]ConstraintsMandates:is_constructible_v<T, initializer_list<I>&, Us...>
istrue
Modify 20.4.2.3 [polymorphic.ctor] as indicated:
template<class U = T> constexpr explicit polymorphic(U&& u);-12- Constraints: Where
UU
isremove_cvref_t<U>
,
(12.1) —
is_same_v<UU, polymorphic>
isfalse
,
(12.2) —derived_from<UU, T>
istrue
,(12.3) —
is_constructible_v<UU, U>
istrue
,(12.4) —
is_copy_constructible_v<UU>
istrue
,(12.5) —
UU
is not a specialization ofin_place_type_t
, and(12.6) —
is_default_constructible_v<Allocator>
istrue
.-?- Mandates:
-13- Effects: […]derived_from<UU, T>
istrue
.template<class U = T> constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u);-14- Constraints: Where
UU
isremove_cvref_t<U>
,
(14.1) —
is_same_v<UU, polymorphic>
isfalse
,
(14.2) —derived_from<UU, T>
istrue
,(14.3) —
is_constructible_v<UU, U>
istrue
,(14.4) —
is_copy_constructible_v<UU>
istrue
, and(14.5) —
UU
is not a specialization ofin_place_type_t
.-?- Mandates:
-15- Effects: […]derived_from<UU, T>
istrue
.template<class U, class... Ts> constexpr explicit polymorphic(in_place_type_t<U>, Ts&&... ts);-16- Constraints:
(16.1) —
is_same_v<remove_cvref_t<U>, U>
istrue
,
(16.2) —derived_from<U, T>
istrue
,(16.3) —
is_constructible_v<U, Ts>
istrue
,(16.4) —
is_copy_constructible_v<U>
istrue
, and(16.5) —
is_default_constructible_v<Allocator>
istrue
.-?- Mandates:
-17- Effects: […]derived_from<U, T>
istrue
.template<class U, class... Ts> constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t<U>, Ts&&... ts);-18- Constraints:
(18.1) —
is_same_v<remove_cvref_t<U>, U>
istrue
,
(18.2) —derived_from<U, T>
istrue
,(18.3) —
is_constructible_v<U, Ts>
istrue
, and(18.4) —
is_copy_constructible_v<U>
istrue
.-?- Mandates:
-19- Effects: […]derived_from<U, T>
istrue
.template<class U, class I, class... Us> constexpr explicit polymorphic(in_place_type_t<U>, initializer_list<I> ilist, Us&&... us);-20- Constraints:
(20.1) —
is_same_v<remove_cvref_t<U>, U>
istrue
,
(20.2) —derived_from<U, T>
istrue
,(20.3) —
is_constructible_v<U, initializer_list<I>&, Us...>
istrue
,(20.4) —
is_copy_constructible_v<U>
istrue
, and(20.5) —
is_default_constructible_v<Allocator>
istrue
.-?- Mandates:
-21- Effects: […]derived_from<U, T>
istrue
.template<class U, class I, class... Us> constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t<U>, initializer_list<I> ilist, Us&&... us);-22- Constraints:
(22.1) —
is_same_v<remove_cvref_t<U>, U>
istrue
,
(22.2) —derived_from<U, T>
istrue
,(22.3) —
is_constructible_v<U, initializer_list<I>&, Us...>
istrue
, and(22.4) —
is_copy_constructible_v<U>
istrue
.-?- Mandates:
-23- Effects: […]derived_from<U, T>
istrue
.