Почему GCC отказывается от ссылки на const в операции копирования-назначения? - PullRequest
1 голос
/ 28 мая 2019

Я хочу перегрузить обычный оператор назначения копирования.Сначала я использовал интерфейс, который требует только константную ссылку на источник, и явно отключил интерфейс, который принимает изменяемую ссылку, но я не могу пропустить компиляцию.Компилятор сообщает «ошибка: использование удаленной функции« ClassA & ClassA :: operator = (ClassA &) »*

Конечно, я могу скомпилироваться, если не удаляю интерфейс точно, но это не моя цель,Я хотел бы явно удалить его, чтобы избежать неожиданного его использования.

Почему для операции копирования-копирования требуется изменяемая ссылка на источник, а не константная ссылка?Операция присваивания просто нуждается в доступе к источнику только для чтения!

Есть такой же вопрос о конструкторе копирования, я его опускаю для упрощения.

Что не так с моим кодом?или мы НЕ можем его удалить?

Мой пример кода следующий:

class ClassA {
public:
   ClassA() = default;
   ClassA( ClassA & ) = default;

   ClassA & operator=( ClassA & )
   = delete   // Must comment-out this, or we can't pass the compilation.
   // { cout << "ClassA & operator=( ClassA & ) executed." << endl; return *this; }
   ;

   ClassA & operator=( ClassA && ) {
      cout << "ClassA & operator=( ClassA && ) executed." << endl;
      return *this;
   };

   ClassA & operator=( const ClassA & ) {
      cout << "ClassA & operator=( const ClassA & ) executed." << endl;
      return *this;
   };
   ClassA & operator=( const ClassA && ) {
      cout << "ClassA & operator=( const ClassA && ) executed." << endl;
      return *this;
   };
};

int main() {
   ClassA oa, ob;
   ob = oa;

   return EXIT_SUCCESS;
};

Ответы [ 3 ]

4 голосов
/ 28 мая 2019

или мы НЕ МОЖЕМ удалить его?

Тебе просто не нужно этого делать. Если вы предоставите пользовательский оператор назначения копирования, то никакие другие не будут неявно объявлены , т. Е. Будет существовать только пользовательский.

Если вы сделаете это, оператор копирования, который вы явно пометили как delete, будет участвовать в разрешении перегрузки; когда он выбран, компиляция не удалась. Для ob = oa; лучше подходит operator=( ClassA & ), если его не существует, будет использоваться operator=( const ClassA & ) и работать нормально.

Так что в этом случае вы можете просто сделать

class ClassA {
public:

   ClassA & operator=( ClassA && ) {
      cout << "ClassA & operator=( ClassA && ) executed." << endl;
      return *this;
   }

   ClassA & operator=( const ClassA & ) {
      cout << "ClassA & operator=( const ClassA & ) executed." << endl;
      return *this;
   }
};
2 голосов
/ 28 мая 2019

Конечно, я могу скомпилироваться, если не удаляю интерфейс точно, но это не моя цель. Я хотел бы удалить его, чтобы избежать неожиданного использования.

Вы не можете неожиданно использовать то, чего не существует. Если ваш класс определяет ClassA & operator=( const ClassA & ), то ClassA & operator=( ClassA & ) вообще не будет существовать (компилятор этого не сгенерирует). Нет причин предоставлять и удалять его.

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

Если вы удалите его, и вы позвоните:

ob = oa;
// The same as
ob.operator=(oa);

Конечно, ClassA & operator=( ClassA & ) - лучшее совпадение, так как oa - неконстантное значение. Поскольку он удален, это будет ошибкой.

Если он вообще не объявлен, ClassA & operator=( const ClassA & ) теперь становится лучшим совпадением. Поэтому он никогда не будет пытаться использовать ClassA & operator=( ClassA & ), поскольку он не существует.

Если вы действительно хотите, у вас все равно может быть ClassA & operator=( ClassA & ) = delete;, и вам придется вручную присваивать из константных ссылок:

ob = static_cast<const ClassA&>(oa);
// Will now select `ClassA & operator=( const ClassA & )`

Это показывает, что вам не нужен неконстантный оператор присваивания lvalue. Но в действительности нет никакого смысла, так как он все равно будет использоваться как ссылка на const, если ClassA & operator=( ClassA & ) не объявлено.

...