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.
std::polymorphic wording seems to imply slicingSection: 20.4.2.3 [polymorphic.ctor], 20.4.2.5 [polymorphic.assign], 20.4.2.4 [polymorphic.dtor] Status: New Submitter: Fraser Gordon Opened: 2026-02-27 Last modified: 2026-03-04
Priority: Not Prioritized
View all issues with New status.
Discussion:
The wording for some member functions of std::polymorphic is imprecise, leading to plausible
interpretations that undermine the purpose of the type (i.e causing slicing on copy/move).
U, where U is the type of
the owned object in other" but the copy/move assignment methods are missing this, which allows
a reading where allocator_traits<Allocator>::construct is called to construct
an instance of value_type instead of U.
A similar reading of the destructor effects would cause ~value_type() to be used instead of
~U(), so that should also be cleaned up.
Finally, the last sentence of the effects of one of the constructors (20.4.2.3 [polymorphic.ctor] p11)
doesn't make sense in context ("constructs an object of type polymorphic, considering the owned object
in other as an rvalue"). As written, this is creating a new polymorphic object and doing nothing
with it when the intended effect would be to construct a new owned object.
Proposed resolution:
This wording is relative to N5032.
Modify 20.4.2.3 [polymorphic.ctor] as indicated:
constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) noexcept(allocator_traits<Allocator>::is_always_equal::value);-11- Effects:
allocis direct-non-list-initialized witha. Ifotheris valueless,*this is valueless. Otherwise, ifalloc == other.allocistrue, either constructs an object of typepolymorphicthat owns the owned object ofother, makingothervalueless; or, owns an object of the same type constructed from the owned object of other considering that owned object as an rvalue. Otherwise, ifalloc != other.allocistrue, constructs anobject of typeowned object of typepolymorphic, consideringU, whereUis the type of the owned object inother, with the owned object inotheras an rvalue, using the allocatoralloc.
Modify 20.4.2.5 [polymorphic.assign] as indicated:
constexpr polymorphic& operator=(const polymorphic& other);-1- Mandates:
-2- Effects: IfTis a complete type.addressof(other) == thisistrue, there are no effects. Otherwise:
(2.1) — […]
(2.2) — If
otheris not valueless, a new owned object of typeU, whereUis the type of the owned object in other, is constructed in*thisusingallocator_traits<Allocator>::constructwith the owned object fromotheras the argument, using either the allocator in*thisor the allocator inotherif the allocator needs updating.(2.3) — […]
(2.4) — […]
constexpr polymorphic& operator=(polymorphic&& other) noexcept(allocator_traits<Allocator>::propagate_on_container_move_assignment::value || allocator_traits<Allocator>::is_always_equal::value);-5- Mandates: If
-6- Effects: Ifallocator_traits<Allocator>::propagate_on_container_move_assignment::valueisfalseandallocator_traits<Allocator>::is_always_equal::valueisfalse,Tis a complete type.addressof(other) == thisistrue, there are no effects. Otherwise:
(6.1) — […]
(6.2) — […]
(6.3) — […]
(6.4) — Otherwise, constructs a new owned object of type
U, whereUis the type of the owned object inother, with the owned object ofotheras the argument as an rvalue, using the allocator in*this.(6.5) — […]
(6.6) — […]
Modify 20.4.2.4 [polymorphic.dtor] as indicated:
constexpr ~polymorphic();-1- Mandates:
-2- Effects: IfTis a complete type.*thisis not valueless,destroys the owned object usingcallsallocator_traits<Allocator>::destroy andallocator_traits<Allocator>::destroy(p), wherepis a pointer of typeU*to the owned object andUis the type of the owned object; then the storage is deallocated.