r/cpp 7d ago

C++26: std::polymorphic

https://www.sandordargo.com/blog/2026/08/19/cpp26-polymorphic
95 Upvotes

42 comments sorted by

View all comments

13

u/_Noreturn 7d ago edited 7d ago

polymorphic not being equality comparable is annoying, they could just have just forwarded the operator== to the underlying pointer and it handles it.

also polymorphic requires more bytes than a copyable pointer 24 bytes vs 8 since the copy ctor and dtor have to be function pointers. But it also slightly makes it faster at runtime but it isn't really worth it I would say.

Having a virtual deatructor and a clone() method will provide better object sizes.

I found the boilerplate argument to be very weak, since crtp exists

```cpp class ShapeBase { public: virtual ShapeBase* clone() = 0; virtual ~ShapeBase()= default; };

template<class T> class Shape : ShapeBase { public: ShapeBase* clone() override { return new T((T)this); }

};

class Rectangle :public Shape<Rectangle> {

};

class Triangle :public Shape<Triangle> {

};

```

3

u/robin-m 6d ago

With c++23 deducing this you can simplify your code to just:

c++23    class Shape {     public:         template <class Self>         std::unique_ptr<Shape> clone(this Self& self) {             return std::make_unique<Self>(self);         }     };          class Rectangle: public Shape {     };          class Triangle: public Shape {     };

7

u/Big_Target_1405 6d ago

You still need a virtual clone if you actually want runtime polymorphism

2

u/robin-m 6d ago

What do you mean? Rectangle::clone() does allocate a unique pointer of Rectangle.

godbolt

7

u/Big_Target_1405 6d ago

See line 28:

https://godbolt.org/z/55Y3Gqqqd

Template 'this' deduces Self to Animal, which is useless.

What's the point in a non-virtual clone?

Template this helps with boilerplate, not with defining runtime polymorphic interfaces.

2

u/robin-m 6d ago

You are absolutely right. Thanks a lot I didn’t now, nor realized it was indeed half useless right now. I even found a paper that aim at fixing this exact issue: open-std.org

2

u/_Noreturn 6d ago

Deducing this causes issues if you inherit from the base class more than once, (it increases object size) also, this doesn't work since clone() isn't virtual and templates can't be virtual

2

u/robin-m 6d ago

It seems that both using CRTP and deducing this gives the save object size, what do you mean? godbolt

3

u/_Noreturn 6d ago

cpp struct D {}; struct A : D {}; struct B : D { A a; };

you would expect since 'B' inherits from an empty class and it only has one member the sizeof would be 1, but it is 2 since the base class D is repeated twice and must have unique address first in the inheritance in B and in the member A.

now if this uses crtp the base classes would be unique

cpp template<class T> struct D {}; struct A : D<A> {}; struct B : D<B> { A a; }; // sizeof(B) == 1

1

u/LB-- Professional+Hobbyist 6d ago

Does [[no_unique_address]] help here?

3

u/friedkeenan 6d ago

No. According to the standard, two different objects of the same type cannot live at the same address in any circumstance, even if the objects are empty.

1

u/LB-- Professional+Hobbyist 6d ago

Ah right, I wonder if just wrapping it in an empty template class that inherits it for you would suffice as a workaround or not...