简体   繁体   中英

Virtual Equal Function between templated classes (C++)

This question is a follow up on Here . The goal was to implement a virtual equal operator between non templated classes. In this question, I am asking for the same goal for a templated class.

#define EQUAL_FOR_BASE(derived)         virtual bool equal(const derived& eq) const { return false; };
#define EQUAL_FOR_DERIVED(this_derived) bool equal(const Equalable& equalable) const { return equalable.equal(*this_derived); };

class RandomClass; //This is for clarification purposes, not used.
class DerivedTemplateType_One;
class DerivedTemplateType_Two;

class Equalable
{
public:
    Equalable() = default;
    virtual ~Equalable() = default;
    virtual bool operator==(const Equalable& eq) { return this->equal(eq); };
    EQUAL_FOR_BASE(RandomClass);
    EQUAL_FOR_BASE(DerivedTemplateType_One);
    EQUAL_FOR_BASE(DerivedTemplateType_Two);
    virtual bool equal(const Equalable& eq) const = 0;
};

class RandomClass : public Equalable
{
public:
    RandomClass() = default;
    ~RandomClass() = default;
    EQUAL_FOR_DERIVED(this);
    virtual bool equal(const RandomClass& rc) const { return m_double == rc.m_double; };
    double m_double;
};

class TemplateType : public Equalable //Still pure virtual due to equal in Equalable.
{
public:
    TemplateType() = default;
    virtual ~TemplateType() = default;
    int m_string;
};


class DerivedTemplateType_One : public TemplateType
{
public:
    EQUAL_FOR_DERIVED(this);
    virtual bool equal(const DerivedTemplateType_One& one) const { return m_int == one.m_int; };
    int m_int;
};

class DerivedTemplateType_Two : public TemplateType
{
public:
    EQUAL_FOR_DERIVED(this);
    virtual bool equal(const DerivedTemplateType_Two& two) const { return m_size == two.m_size; };
    std::size_t m_size;
};

template<typename T>
class Target : Equalable
{
public:
    T m_t;
};

Q1 : I want to limit the template typename T above to be a derived class of TemplateType (derived from Equalable) eg Can be DerivedTemplateType_One/Two (Of course there will be Three, Four..)? Isn't there static_assert or some metaprogramming to check this at compile time or would:

template<TemplateType DerivedTypeOneOrTwo>
class Target : public Equalable
{
public:
    DerivedTypeOneOrTwo m_t;
};

Work?

Q2 : How can I implement the equal operator as I did for RandomClass please?

Q3 : I am asking about Q1 in order to limit template types possible so that Q2 is possible, can I generalize Q1: Limit template typename T to classes inheriting from Equalable (instead of TemplateType ) and still do Q2?

Sorry this is getting a bit complicated but there is no easy way:) Thanks very much!!

Ps: I am making everything public to save space, please ignore.

I ended using CRTP if anyone is interested (Please let me know if I am doing something wrong I missed)

template<class Derived>
class Equalable
{
public:
    using derived_type = Derived;
    bool operator==(const Derived& derived) const { return this->equal(derived); };
    bool operator!=(const Derived& derived) const { return !(*this == derived); }
    
private:
    virtual bool equal(const Derived& derived) const = 0;
};

class B : public Equalable<B>
{
public:
    B(double d) : m_example(d) {};
private:
    virtual bool equal(const B& derived) const override { return derived.m_example == m_example; };
    double m_example;
};

class A : public Equalable<A>
{
public:
    A(std::string d) : m_example(d) {};
private:
    virtual bool equal(const A& derived) const override { return derived.m_example == m_example; };
    std::string m_example;
};

Now we can compare element of same type:

int main()
{
    A a("string");
    B b(1);
    A aa("other_string");
    B bb(11);
    std::cout << (a == aa) << std::endl; //Ok
    std::cout << (b == bb) << std::endl; //Ok
    std::cout << (a == b) << std::endl;  //Wrong, not supported.
};

I tried doing this:

template<class A, class B>
static bool equal(const Equalable<A>& a, const Equalable<B>& b)
{
    if (!std::is_same<A, B>::value)
        return false;
    return a == b;
};

But didn't compile, so I just used equality between same types.

To limit template (As of Question Q1) there a standard check:

static_assert(std::is_base_of<Base, Derived>::value, "Only from Base");

Hope you have better suggestions, I still don't like this:) Thanks everyone!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM