Компилятор сообщает об "удаленном" операторе =, но он есть

Я столкнулся с неприятной проблемой, когда компилятор требует operator= удален, но он есть. После нескольких часов попыток я нашел минимальное решение, которое воспроизводит проблему. Я использую MSVC Community Edition 2017 15.7.5 (самая последняя на сегодняшний день, 2018-07-20) и установил для него "C++17"

Код не тривиален; концепция заключается в том, что шаблонный класс TT используется для обеспечения существования статической функции-члена foo в группе классов Fn, Это очень похоже на шаблон фабрики, только это решение не создает экземпляры класса, но сообщает статическую подробную информацию о классе.

Ошибка присваивается в присваивании в последней строке и читается (полный список ошибок внизу):

"ошибка C2280:" C &C::operator =(const C &) ": попытка сослаться на удаленную функцию"

Но строка 5 определила этот оператор, верно с этими декораторами?

Сбой назначения пытается присвоить возвращаемое const std::vector<C>& к переменной члена класса.
Я думал const создает проблему, но удаляет все const в каждой функции нет никакой разницы; та же ошибка в той же строке.

Вопрос: почему компилятор сообщает об этом и что можно исправить?
Я думаю, что это должно быть что-то глупое, я скучаю, но я не могу найти это.

#include <vector>

class C
{
public:
  C(int ii) : i(ii) {}
  C& operator=(const C&) = default;    /// HERE is the assignment operator
  const int i;
};
typedef std::vector<C> CVec;   // shorthand for a vector of C's

template <class T>   // this template forces classes F1, F2, ... to have a static member function 'foo'
class TT {
public:
  static const CVec& foo(void) { return T::foo(); }
};

class F1  // one of many Fn classes
{
public:
  static const CVec& foo(void) { static CVec cv{ C{ 1 }, C{ 2 } }; return cv; }    // static member as forced by template
  //...
};
class F2  // another one of many Fn classes
{
public:
  static const CVec& foo(void) { static CVec cv{ C{ 3 } }; return cv; }     // static member as forced by template
  //...
};

class D    // controller class
{
public:
  CVec cv;
  const CVec& bar(int z)   // function to select one of the subclasses
  {
    switch (z)
    {
      case 1: return TT<F1>::foo();
      case 2: return TT<F2>::foo();
        //...
    }
  }

  void foobar(void)  //selector (from user input)
  {
    int z = 2; // user input
    cv = bar(z);   // THIS assignment produces the error
  }
};

Полный текст ошибки:

------ Build started: Project: BG, Configuration: Debug Win32 ------
bgcore.cpp
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\xutility(2443): error C2280: 'C &C::operator =(const C &)': attempting to reference a deleted function
d:\projects\bg\core\bgcore.h(8): note: see declaration of 'C::operator ='
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\xutility(2462): note: see reference to function template instantiation '_OutIt std::_Copy_unchecked1<_InIt,_OutIt>(_InIt,_InIt,_OutIt,std::_General_ptr_iterator_tag)' being compiled
        with
        [
            _OutIt=C *,
            _InIt=C *
        ]
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\vector(1430): note: see reference to function template instantiation '_OutIt *std::_Copy_unchecked<_Iter,C*>(_InIt,_InIt,_OutIt)' being compiled
        with
        [
            _OutIt=C *,
            _Iter=C *,
            _InIt=C *
        ]
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\vector(1448): note: see reference to function template instantiation 'void std::vector<C,std::allocator<_Ty>>::_Assign_range<_Iter>(_Iter,_Iter,std::forward_iterator_tag)' being compiled
        with
        [
            _Ty=C,
            _Iter=C *
        ]
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\vector(1448): note: see reference to function template instantiation 'void std::vector<C,std::allocator<_Ty>>::_Assign_range<_Iter>(_Iter,_Iter,std::forward_iterator_tag)' being compiled
        with
        [
            _Ty=C,
            _Iter=C *
        ]
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\vector(1471): note: see reference to function template instantiation 'void std::vector<C,std::allocator<_Ty>>::assign<C*,void>(_Iter,_Iter)' being compiled
        with
        [
            _Ty=C,
            _Iter=C *
        ]
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\vector(1471): note: see reference to function template instantiation 'void std::vector<C,std::allocator<_Ty>>::assign<C*,void>(_Iter,_Iter)' being compiled
        with
        [
            _Ty=C,
            _Iter=C *
        ]
c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\vector(1457): note: while compiling class template member function 'std::vector<C,std::allocator<_Ty>> &std::vector<_Ty,std::allocator<_Ty>>::operator =(const std::vector<_Ty,std::allocator<_Ty>> &)'
        with
        [
            _Ty=C
        ]
d:\projects\bg\core\bgcore.h(49): note: see reference to function template instantiation 'std::vector<C,std::allocator<_Ty>> &std::vector<_Ty,std::allocator<_Ty>>::operator =(const std::vector<_Ty,std::allocator<_Ty>> &)' being compiled
        with
        [
            _Ty=C
        ]
d:\projects\bg\core\bgcore.h(22): note: see reference to class template instantiation 'std::vector<C,std::allocator<_Ty>>' being compiled
        with
        [
            _Ty=C
        ]
Done building project "BG.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

3 ответа

Вот гораздо более короткая версия вашей проблемы:

class C
{
public:
  C(int ii) : i(ii) {}
  C& operator=(const C&) = default;
  const int i;
};

C a(1);
a = a; // error: use of deleted function

Хотя вы по умолчанию использовали функцию, это не значит, что она обязательно действительна. Это просто означает, что вы явно по умолчанию. Оператор присвоения копии по умолчанию будет копировать-присваивать все подобъекты и элементы по одному. Но ваш единственный член const int, и вы не можете скопировать-назначить это! Это const!

Конкретное правило находится в [class.copy.assign] / 7:

Оператор присвоения по умолчанию для копирования / перемещения для класса X определяется как удаленный, если X имеет: [...] элемент не статических данных const неклассный тип (или его массив), или [...]

Сделайте участника просто int iи ты в порядке.

Вам всегда разрешено = default специальная функция-член. Это облегчает подчинение правилу ноль или пять. Это дает читателю понять, что вы рассмотрели этот элемент и хотите поведение по умолчанию.

Как было указано, вы не можете по умолчанию использовать конструктор копии присваивания, который был удален, потому что член . Это связано с тем, что в С++ 17 или более ранних версиях не было возможности изменить объект. Вы могли бы написать конструктор копирования присваивания, но по-прежнему не было возможности скопировать элемент const.

Это изменилось в С++ 20, и теперь вы можете делать это на законных основаниях.

Если вы измените

      C& operator=(const C&) = default;    /// HERE is the assignment operator

к

      C& operator=(const C& from)
{
if (this!= &from)
{
   std::destroy_at(this);
   std::construct_at(this, from);
}
Другие вопросы по тегам