Wednesday, 29 June 2011

Co-variant returns

Co-variant return types. Don't you just love them?

struct Base {
    virtual Base* do_something() = 0;
};
struct Derived : public Base {
    Derived* do_something() { return this; }
};


But as per usual, this particular feature wasn't properly thought through. After all, what if I need to use an owning pointer? Only raw pointers are co-variant.

struct Base {
    virtual std::unique_ptr<Base> do_something() = 0;
};
struct Derived : public Base {
    virtual std::unique_ptr<Derived> do_something() { 

        return std::unique_ptr<Derived>(new Derived(*this)); 
    }
};


Oops - not allowed. What, are my UDTs second class citizens now? I think that this rule should be widened to allow any implicit conversion, especially now that we have explicit conversion operators in C++0x.

There are other examples of this problem.

template<typename T, typename U> void CheckType(T* t) {
    if (!dynamic_cast<U*>(t)) {
        // Whoops
    }
}


Ok- for raw pointers. But, of course, we can't do that for shared_ptr, so it's time to overload.

template<typename T, typename U> void CheckType(std::shared_ptr<T> t) {
    if(!std::dynamic_pointer_cast<U*>(t)) {
        // Whoops
    }
}


Of course, unique_ptr doesn't even provide such a facility, so we'll have to come up with something else- probably using get().

template<typename T, typename U> void CheckType(const std::unique_ptr<T> t) {
    if (!dynamic_cast<U*>(t.get())) {
        // Whoops
   }
}


I sure hope that I don't have more than a couple smart pointer types, or I'm gonna be here all day. Just let me overload dynamic_cast and be done with it. Why bother allowing us to overload only some pointer operations? This would also allow much more natural syntax for libraries that implemented their own- like QueryInterface() in COM, and LLVM has one and I think that Qt also has one. Some newer COM interfaces come with a nice template wrapper on QueryInterface() that takes away some of the headache, but it's still not the same as actually supporting dynamic_cast and being generic.

No comments:

Post a Comment