具有模板容器的协变返回类型

Covariant Return Type With Template Container

本文关键字:返回类型      更新时间:2023-10-16

是否可以进行以下工作?基本上,我希望 Ptr 成为 Ptr 可接受的返回类型替代品。

template<typename T>
class Ptr {
public:
    explicit Ptr (T * ptr) : ptr(ptr) {}
    T * ptr;
};

class A {
    virtual Ptr<A> foo () {
        return Ptr<A>(NULL);
    }
};
class B : public A {
    virtual Ptr<B> foo () { // BAD! Ptr<B> is not compatable
        return Ptr<B>(NULL);
    }
};

您可以使用奇怪的重复模板将虚拟函数重载替换为模板函数返回。以下文章可能会有所帮助:

http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

另请检查以下代码:

template <class C_>
class A_Base {
    Ptr<C_> foo() {
        return static_cast<C_*>(this)->foo_impl();
    }
}
class A : public A_Base<A> {
    Ptr<A> foo_impl() { return Ptr<A>(NULL); }
}
class B : public A_Base<B> {
   Ptr<B> foo_impl() { return Ptr<B>(NULL); }
}

根据标准:

重写函数的返回类型

应与被重写函数的返回类型相同,或与函数的类协变。如果函数 D::f 覆盖函数 B::f,则函数的返回类型在满足以下条件时是协变的:

  • 两者都是指向类的指针或对类的引用
  • 返回类型 B::f 中的类与返回类型 D::f
  • 中的类是同一类,或者是返回类型 D::f 中类的明确直接或间接基类,可在 D 中访问
  • 这两个指针或引用具有相同的 CV 限定,并且返回类型 D::f 中的类类型与返回类型 B::f 中的类类型具有相同的 CV 限定或更少的 CV 限定。

因此,在您的示例中,返回类型并不是真正的协变(它们不是指针也不是引用),而且Ptr<B>Ptr<A>是不相关的类型。

因此,将 foo 保持虚拟并在 A 中返回 Ptr<A>,在 B 中返回Ptr<B>是不可能的。如果你可以/愿意放弃虚拟,那么你就可以在Cem Kalyoncu的提议或其变体中使用一些东西。

你可以尝试这样的事情:

template<class T> class Ptr
{
...
};
template<class T> class A
{
    virtual Ptr<T> foo();
};
class B : public A<B>
{
    virtual Ptr<B> foo();
};