I have a class that uses the pimpl idiom.
class MyImpl;
class MyClass
{
public:
private:
MyImpl* _impl;
};
Now I'd like to add spaceship operator support to this class. Ideally I would write something like:
auto operator<=>(const MyClass& rhs) const
{
return *_impl <=> *rhs._impl;
}
The implementation is not known in the header file though. Hence, I have to write the implementation in the source file. But that prevents the usage of auto as a return type. I have to be explicit on whether it's std::strong_ordering, std::weak_ordering or std::partial_ordering. But that heavily depends on the details of MyImpl. If MyImpl contains only ints, the return type would be std::strong_ordering, but if it would contain floats too it would be std::partial_ordering.
I'd like the class declaration of MyClass not to change too much. What's a way to keep its api stable, while still allowing changing member types of MyImpl. I guess it's not ideal to just always return std::partial_ordering.
No, it doesn't.
I mean yes, in a literal in-code sense, the details of the comparison are determined by
MyImpl. But the comparison category of a type is not a private element of that type. It's a public interface, and that public interface needs to be defined.In its entirety.
This is no different from any public member of a Pimpl'd type. If the type has a public interface and a private implementation, the two functions must be in sync. Any changes to one must be propagated to the other.
C++ Pimpl is not DRY. Indeed, it often involves a lot of redundancy. That's just the nature of the idiom.
And you have therefore changed the public interface of that class. You have changed when and how the user can compare instances of that type.
This is not a private matter, so the public interface needs to change accordingly.