Title
Imprecise `std::polymorphic` wording seems to imply slicing
Status
new
Section
[polymorphic.ctor] [polymorphic.assign] [polymorphic.dtor]
Submitter
Fraser Gordon

Created on 2026-02-27.00:00:00 last changed 7 days ago

Messages

Date: 2026-03-02.13:33:43

Proposed resolution:

This wording is relative to N5032.

  1. 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.

  2. 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) — […]

  3. 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.

Date: 2026-03-02.13:33:43

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:00adminsetmessages: + msg15997
2026-02-27 00:00:00admincreate