Ковариантный тип возврата с контейнером шаблона - PullRequest
3 голосов
/ 12 мая 2011

Можно ли сделать следующую работу?По сути, я хочу, чтобы 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);
    }
};

Ответы [ 3 ]

4 голосов
/ 12 мая 2011

Вы можете использовать любопытно повторяющиеся шаблоны для замены перегрузок виртуальных функций возвратами из функций шаблонов. Следующая статья может помочь:

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); }
}
1 голос
/ 12 мая 2011

Согласно стандарту:

Тип возврата переопределяемой функции должен быть либо идентичным типу возврата переопределенной функции, либо ковариантно классам функций. Если функция D :: f переопределяет функцию B :: f, возвращаемые типы функций ковариантны, если они удовлетворяют следующим критериям:

  • оба являются указателями на классы или ссылками на классы
  • класс в возвращаемом типе B :: f является тем же классом, что и класс в возвращаемом типе D :: f или, является однозначным прямым или косвенным базовым классом класса в возвращаемом типе D: : f и доступен в D
  • и указатели, и ссылки имеют одинаковую квалификацию cv, а тип класса в возвращаемом типе D :: f имеет ту же квалификацию cv, что и квалификационная квалификация cv или меньше, чем тип класса в возвращаемом типе B :: е.

Таким образом, в вашем примере возвращаемые типы не являются ковариантными (они не являются ни указателями, ни ссылками), и, кроме того, Ptr<B> и Ptr<A> являются несвязанными типами.

Таким образом, сохранение виртуального foo и возврат Ptr<A> в A и Ptr<B> в B невозможно. Если вы можете / хотите отказаться от виртуального, вы можете использовать что-то в соответствии с предложением Джема Калионку или его вариантом.

0 голосов
/ 05 октября 2016

Вы можете попробовать что-то вроде этого:

template<class T> class Ptr
{
...
};

template<class T> class A
{
    virtual Ptr<T> foo();
};

class B : public A<B>
{
    virtual Ptr<B> foo();
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...