CRTP и копирование / перемещение назначения / наследования конструктора - PullRequest
2 голосов
/ 02 мая 2019

Я пытаюсь реализовать операторы и конструкторы назначения перемещения / копирования в базовом классе для производных классов с использованием CRTP.

template <typename Derived>
class base {
public:
    Derived& operator= (const Derived& other) {
        // Copy the base properties:
        this->foo_ = other.foo_;
        // ...
        // Continue as the derived class demands it:
        this->derived().copy(other);
        return this->derived();
    }
    // etc. for copy/move assignment/construction...

private:
    // To act as the derived class:
    Derived& derived () { return *static_cast<Derived*>(this); }
    const Derived& derived () const { return *static_cast<const Derived*>(this); }

protected:
    // Some base properties:
    int foo_;
    // ...
};

class derived: public base<derived> {
    friend base<derived>;

public:
    // Inheriting the constructors and assignment operators:
    using base<derived>::base;
    using base<derived>::operator=;

private:
    void copy (const derived& other) {
        // Copy all the needed derived properties:
        this->bar_ = other.bar_;
        // ...
    }

    // Some derived properties:
    int bar_;
    // ...
};

// To test it:
int main () {
    derived d, t;
    d = t;
}

Компилятор выдает мне сообщение о том, что derived& derived::operator=(const derived&) нельзя перезаписать с помощью derived& base<derived>::operator=(const derived&). Моя теория такова, что каким-то образом derived::operator= определяется неявно, а затем, вводя base<derived>::operator= декларацией using, я пытаюсь переопределить его еще раз, может быть? Это выглядит подозрительно похоже на ошибки, возникающие при случайном определении метода дважды.

Я скомпилировал это с GCC, и полный журнал:

test.cpp: In function 'int main()':
test.cpp:25:7: error: 'constexpr derived& derived::operator=(const derived&)' cannot be overloaded
 class derived: public base<derived> {
       ^~~~~~~
test.cpp:4:14: error: with 'Derived& base<Derived>::operator=(const Derived&) [with Derived = derived]'
     Derived& operator= (const Derived& other) {
              ^~~~~~~~

Возможно ли это сделать, или мне нужно определить операторы / конструкторы в классе derived и затем делегировать их функциональность классу base внутри определения?

Обновление

Хорошо, возможно, после более ясного взгляда на это, это кажется слишком сложным. Я мог бы просто сделать следующее:

Derived& base<Derived>::operator= (const base& other) {
    this->foo_ = other.foo_;
    return this->self();
}

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

// Adding this to the base class - for any derived class to act as the base one:
template <Derived>
base<Derived>& base<Derived>::base () { *return static_cast<base<Derived>*>(this); }

derived& derived::operator= (const derived& other) {
    this->base() = other.base();
    this->bar_ = other.bar_;
}

Но, тем не менее, это интересное упражнение, и вопрос об ошибке компилятора остается без ответа.

1 Ответ

1 голос
/ 03 мая 2019

Вы не можете с пользой объявить «производное operator=» с обычной подписью в базовом классе, потому что, даже с using-объявлением , оно всегда скрыто неявно заявленный оператор присвоения копии . (Вы можете использовать какую-то другую подпись для одного или обоих, но тогда разрешение перегрузки может быть… интересным.)

Между тем, вы обнаружили ошибку GCC в том, что она неверно заключает, что два оператора конфликтуют, а не один скрывает другого.

...