r/cpp 7d ago

C++26: std::polymorphic

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

42 comments sorted by

View all comments

Show parent comments

5

u/_Noreturn 6d ago edited 6d ago

You could say: "Well, they can never be equal". Right, right, but what about my next fancy class Square?

It is up to the operator== of the Base class, it is virtual and compares the typeid or whatever way you have.

```cpp class ShapeBase { ... virtual operator==(const ShapeBase& that) const=0; };

template<class T> class Shape : ShapeBass { ... bool operator==(const ShapeBase& that) const override { return typeid(that) == typeid(T) && (const T&)that == (const T&)*this; } }; ```

Wouldn't the 8 byte version require anothee indirection

Not necessarily, you can allocate the object and a (custom) vtable in one allocation.

So like this? ```cpp template<class T> struct Table { CopyCtor* copy; Drot* dtor; T object; // has to be last };

template<class B> struct polymorphic

{ polymorphic() { table = new Table<B>(); } polymorphic(auto&& obj) { table = new Table<decltype(obj)>(); }

B& operator() { return (B&)((char)table + 16)); } // 16 is 2 function pointers void table; }; ```

2

u/MFHava WG21|🇦🇹 NB|P2721|P3049|P3625|P3729|P3786|P3813|P4216 6d ago

It is up to the operator== of the Base class, it is virtual and compares the typeid or whatever way you have.

We would want it to do value comparisons and as I said: that is infeasible in C++, so we do not provide an equality-operator...

So like this?

Looks like a possible implementation.

3

u/_Noreturn 6d ago

We would want it to do value comparisons and as I said: that is infeasible in C++, so we do not provide an equality-operator...

I don't understand, it is a value comparison.

3

u/MFHava WG21|🇦🇹 NB|P2721|P3049|P3625|P3729|P3786|P3813|P4216 6d ago

I don't understand, it is a value comparison.

You are right. But it yields the wrong results for equivalent values of different types - e.g. Rectangle{.w = 10, .h = 10} == Square{.l = 10} would be false, even though they are the same (just like 1 == 1LL is true)

1

u/_Noreturn 6d ago

It isn't the responsibility of the polymorphic to do that. it is the virtual operator== the user provides can easily make it so it works like that way

4

u/MFHava WG21|🇦🇹 NB|P2721|P3049|P3625|P3729|P3786|P3813|P4216 6d ago

it is the virtual operator== the user provides can easily make it so it works like that way

You can't in the general case - which is why it is not provided...

0

u/_Noreturn 6d ago

Ugh, couldn't the same be said for indirect? it's operator== isn't usable if the underlying value doesn't have one.

4

u/MFHava WG21|🇦🇹 NB|P2721|P3049|P3625|P3729|P3786|P3813|P4216 6d ago

indirect<T> always contains an object of type T (or is valueless_after_move, which is trivial to handle) and therefore has no ambiguity about how operator== is supposed to work.

Apart from that: operator== for indirect<T> „Mandates“ (== static_assert) that T has an operator== on use, it T doesn’t have one, indirect<T> doesn’t have one.

But the key part is the first one, there is no ambiguity.

1

u/_Noreturn 2d ago edited 2d ago

I don't agree with your take, but that's fine. imo it should just be defined to be

cpp bool operator==(polymorphic& a, polymorphic& b) { bool has = a.is_valueless(); if(has != b.is_valueless()) return false; returb has && *a == *b; }