Created on 2026-02-27.00:00:00 last changed 7 days ago
Proposed resolution:
This wording is relative to N5032.
Modify [polymorphic.ctor] as indicated:
constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) noexcept(allocator_traits<Allocator>::is_always_equal::value);-11- Effects: alloc is direct-non-list-initialized with `a`. If `other` is valueless, `*this is valueless`. Otherwise, if alloc == other.alloc is `true`, either constructs an object of type `polymorphic` that owns the owned object of `other`, making `other` valueless; or, owns an object of the same type constructed from the owned object of other considering that owned object as an rvalue. Otherwise, if alloc != other.alloc is `true`, constructs an
object of type `polymorphic`, consideringowned object of type `U`, where `U` is the type of the owned object in `other`, with the owned object in `other` as an rvalue, using the allocator alloc.
Modify [polymorphic.assign] as indicated:
constexpr polymorphic& operator=(const polymorphic& other);-1- Mandates: `T` is a complete type.
-2- Effects: If `addressof(other) == this` is `true`, there are no effects. Otherwise:
(2.1) — […]
(2.2) — If `other` is not valueless, a new owned object of type `U`, where `U` is the type of the owned object in other, is constructed in `*this` using allocator_traits<Allocator>::construct with the owned object from `other` as the argument, using either the allocator in `*this` or the allocator in `other` if 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 allocator_traits<Allocator>::propagate_on_container_move_assignment::value is `false` and allocator_traits<Allocator>::is_always_equal::value is `false`, `T` is a complete type.
-6- Effects: If `addressof(other) == this` is `true`, there are no effects. Otherwise:
(6.1) — […]
(6.2) — […]
(6.3) — […]
(6.4) — Otherwise, constructs a new owned object of type `U`, where `U` is the type of the owned object in `other`, with the owned object of `other` as the argument as an rvalue, using the allocator in `*this`.
(6.5) — […]
(6.6) — […]
Modify [polymorphic.dtor] as indicated:
constexpr ~polymorphic();-1- Mandates: `T` is a complete type.
-2- Effects: If `*this` is not valueless,destroys the owned object using allocator_traits<Allocator>::destroy andcalls allocator_traits<Allocator>::destroy(p), where `p` is a pointer of type `U*` to the owned object and `U` is the type of the owned object; then the storage is deallocated.
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).
The wording on most copy/assign methods includes a clause "of type `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 ([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.| History | |||
|---|---|---|---|
| Date | User | Action | Args |
| 2026-02-28 16:02:00 | admin | set | messages: + msg15997 |
| 2026-02-27 00:00:00 | admin | create | |