3

As I understand it, std::polymorphic<T> and std::indirect<T> are const-propagating wrapper types for an owning pointer to a T object, where the target of the pointer is copied with the pointer itself. Simplifying a bit, either can be thought of as “a std::unique_ptr<T> that can be copied”, with the main difference between them being that std::indirect<T> will always point to an object of the exact type T, while std::polymorphic<T> can potentially hold a pointer to an object of a derived type.

But there is a major difference from std::unique_ptr:

struct Base {};
struct Derived : Base {};

std::unique_ptr<Base> p = std::make_unique<Derived>();      // OK
std::indirect<Base> id = std::indirect<Derived>();          // error
std::polymorphic<Base> pm = std::polymorphic<Derived>();    // error

I can understand why this would fail for std::indirect – after all, this conversion, if even allowed at all, would need to slice, which is usually unwanted, so it'd better not happen by accident. I am much more puzzled that it doesn’t work for std::polymorphic either.

I saw in P0206R6 that at one point, back when it was still being proposed as std::polymorphic_value, such a conversion was even supposed to be implicit, but later it was changed to explicit, and by the time the proposal merged with P1950R2 into a joint paper P3019, the conversions disappeared completely. No such constructor is present at [polymorphic.ctor] in the latest draft.

It seems that a std::polymorphic<T> can only be move-constructed or move-assigned from another std::polymorphic<T>, and the best one can do to construct one from the target of a std::polymorphic<U> pmu (with U deriving from T) is via std::move(*pmu), which is less efficient as it constructs a new object and leaves the target-of-the-source in a moved-from state, instead of transferring the allocation directly from the source to the destination and leaving the source valueless, like it happens with same-target-type moves.

Why did this capacity disappear entirely?

1 Answer 1

5

P3019R14 has a section about this on page 27:

Explicit conversions

The older class template polymorphic_value had explicit conversions, allowing construction of a polymorphic_value<T> from a polymorphic_value<U>, where T was a base class of U.

polymorphic_value<Quadrilateral> q(std::in_place_type<Rectangle>, w, h);
polymorphic_value<Shape> s = q;
assert(dynamic_cast<Rectangle*>(&*s) != nullptr);

Similar code cannot be written with polymorphic as it does not allow conversions between derived types:

polymorphic<Quadrilateral> q(std::in_place_type<Rectangle>, w, h);
polymorphic<Shape> s = q; // error

This is a deliberate design decision.
polymorphic is intended to be used for ownership of member data in composite classes where compiler-generated special member functions will be used.

There is no motivating use case for explicit conversion between derived types outside of tests.

A converting constructor could be added in a future version of the C++ standard.

So the answer is that the standard committee did not see a good enough use-case for this to be useful, so it was omitted.

Sign up to request clarification or add additional context in comments.

1 Comment

How silly of me to have missed it. As for use cases, I think I found one, but eventually, I managed to replace it with std::in_place_type

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.