Вернуть ссылку на это и наследство - PullRequest
2 голосов
/ 13 февраля 2012

Для некоторого синтаксического сахара я хочу вернуть ссылку на this, но при наследовании функция должна возвращать тип дочернего класса:

class base {
  T &operator!() { return *this; }
};
base b; b = !b;

class child : public base {};
child c; c = !c;

Из-за оператора я могу 'т просто вернуть указатель и dynamic_cast это, это должна быть ссылка.

Это вообще возможно?Использование decltype(*this) для T не работает, как и auto f()->decltype(*this), из-за this (хотя я не понимаю, почему в автоматическом случае)

В Scala вы можете написать что-то вроде:

template<typename T> class base {
  T &f() { return *this; }
};
class child : public base<child> {};

Но мой g ++ не примет это (не уверен, что это ошибка или нет в спецификации?)

Конечно, есть явный способ, но мне интересно, если этоможно избежать с помощью функций C ++ 11?

class child : public base {
  child &operator!() { base::operator!(); return *this }
};

Ответы [ 2 ]

1 голос
/ 13 февраля 2012

Вы можете использовать CRTP для этого, если вам разрешено сделать base шаблон:

template <typename Derived> class Base {
protected:
    Derived& refToThis() {
        return *static_cast<Derived*>(this);
    }
};

Обратите внимание на дополнительный актерский состав здесь.Причина, по которой это работает, заключается в том, что если у вас есть такой класс:

class Subclass: public Base<Subclass> {
    /* ... */
};

Тогда, если вы вызовете refToThis изнутри этого класса, он вызовет версию базового класса.Поскольку класс наследует от Base<Subclass>, созданный шаблон для refToThis будет

    Subclass& refToThis() {
        return *static_cast<Subclass*>(this);
    }

Этот код безопасен, поскольку указатель this действительно указывает на объект Subclass.Более того, static_cast гарантирует, что приведение завершится неудачно во время компиляции, если производный класс не наследует от Base должным образом, так как тип указателя не будет конвертируемым.

Причина, по которойприведение необходимо здесь: если вы просто скажете

template <typename Derived> class Base {
protected:
    Derived& refToThis() {
        return *this;
    }
};

, тогда в программе будет ошибка типа, поскольку Base само по себе равно , а не a Derived, иесли бы вы могли конвертировать Base& в Derived& без каких-либо проверок, вы могли бы сломать систему типов.

Тем не менее ... Я бы не стал этого делать вообще.Перегрузка operator! для этой цели делает код менее читабельным, а простое написание *this настолько идиоматично, что его скрытие сделает ваш код намного сложнее для понимания.Использование всего этого механизма шаблонов, чтобы избежать чего-то общего с C ++, кажется ошибочным.Если вы делаете что-то еще, прежде чем возвращать ссылку, это нормально, но это не кажется хорошей идеей.

Надеюсь, это поможет!

0 голосов
/ 13 февраля 2012

Пожалуйста, не делай этого.Уже есть способ сделать это на языке *whatever_pointer_you_want_to_use_this_crazy_operator_upon.Создание нового способа сделать что-то на языке просто запутает ваших будущих сопровождающих.Есть ли что-то еще , которое вы на самом деле пытаетесь достичь здесь?

...