Search code examples
c++classtemplatesg++c++23

How can I write a templated C++23 class, which provide operator implementations for its derivatives?


I would like to have a (templated) base class, which, beyond common properties, already implements the operators for the derived classes.

The code I had is:

#include <concepts>
#include <optional>

template <class CLAZZ>
    requires(std::derived_from<CLAZZ, MyBaseClass<CLAZZ>>)
class MyBaseClass
{
    // Has some base properties
public:
    bool operator==(const CLAZZ other) const
    {
        return true; // For sure this is more complex
    }

    bool operator==(const std::optional<const CLAZZ> other) const
    {
        return true; // For sure this is more complex
    }
};

class MyDerivatedClass : public MyBaseClass<MyDerivatedClass>
{
    // More properties added
};

Thinking twice about it, it was clear that this cannot work, because the operators would need types, which does not exist so far.

Because of that, I use just the current class, instead of the final class, despite this brings the risk that accidentally two derived classes exist, which should not have a compatible comparison (safety precaution, would not really become a problem for my use-case I guess).

#include <concepts>
#include <optional>

template <class CLAZZ>
    requires(std::derived_from<CLAZZ, MyBaseClass<CLAZZ>>)
class MyBaseClass
{
    // Has some base properties
public:
    bool operator==(const MyBaseClass<CLAZZ> other) const
    {
        return true; // For sure this is more complex
    }

    bool operator==(const std::optional<const MyBaseClass<CLAZZ>> other) const
    {
        return true; // For sure this is more complex
    }
};

Unfortunately even then I get an error in requires clause, that MyBaseClass is not defined so far.

I then tried with a forward definition, which tells me that the requires clause is incompatible:

template <class CLAZZ>
class MyBaseClass;

Any suggestions how I could implement this and ensure that the operators only work with the derived class itself or at least only for the derivatives of this base class with a matching template argument?


Solution

  • Alter your example to use deduced this:

    class MyBaseClass
    {
    public:
        template <typename Self>
        constexpr bool operator==(this const Self& self, const Self& other)
        {
            return true;
        }
    };
    
    class MyDerivedClass : public MyBaseClass { };
    
    static_assert(MyDerivedClass() == MyDerivedClass());
    

    Because both arguments to operator== are of the same derived type, it cannot compare unrelated derived classes.