Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally enforce template types in c++

Tags:

c++

templates

I have a class template that needs to be able to compare between two objects, via comparison objects derived from a Compare class I have:

template<typename T>
class Container {
public:
    template<typename A, typename B>
    class Compare {
    public:
        virtual bool eq(const A&, const B&) const = 0;
    };

I provide a default comparison objects, assuming type T has the operator ==:

    template<typename A, typename B>
    class Default : public Compare<A,B> {
    public:
        bool eq(const A& a, const B& b) const { return a==b; }
    };
private:
    Compare<T,T>* comparison_object;
    bool uses_default;
    Container() : comparison_object(new Default<T,T>()), uses_default(true) {}
    Container(Compare<T,T>& cmp) : comparison_object(&cmp), uses_default(false) {}
    ~Container() { if(uses_default) delete comparison_object; }
};

However, when I try to compile this with a custom class that does not have an operator== overload (even if I provide an object derived from Compare):

MyObjCmp moc;
Container<MyObj>(&moc);

The compiler complains that the operator doesn't exist:

error: no match for 'operator==' (operand types are 'const MyObj' and 'const MyObj')

This makes sense, because the Default class still needs to be created, even though I don't need it. But now I need a workaround...

Any ideas?

like image 642
Dori Avatar asked Nov 28 '14 12:11

Dori


1 Answers

Rather than a run-time check for a null pointer, you could use a compile-time check for no object:

Container() : comparison_object(new Default<T,T>), uses_default(true) {}
Container(Compare<T,T>& cmp) : comparison_object(&cmp), uses_default(false) {}

The default constructor, and hence Default, will only be instantiated if needed, so there's no error when using the non-default constructor with a type for which Default would fail.

But be careful juggling raw pointers like that, it's a recipe for memory leaks and worse. Don't forget the virtual destructor for Compare and the Rule of Three, and be very careful that a non-default comparator doesn't get unexpectedly destroyed. Better still, use a smart pointer to take care of all that for you.

like image 86
Mike Seymour Avatar answered Nov 15 '22 22:11

Mike Seymour