Почему мне не предоставлен конструктор копии по умолчанию из изменчивого?

Этот код:

class X {
  int member;  
};

volatile X a;
X b = a;

Ошибка с ошибкой:

prog.cpp:6:7: error: no matching function for call to ‘X::X(volatile X&)’
prog.cpp:6:7: note: candidates are:
prog.cpp:1:7: note: X::X()
prog.cpp:1:7: note:   candidate expects 0 arguments, 1 provided
prog.cpp:1:7: note: X::X(const X&)
prog.cpp:1:7: note:   no known conversion for argument 1 from ‘volatile X’ to ‘const X&’

Есть ли способ заставить компилятор генерировать для меня конструктор летучих копий?

Ответ 1

Короткий ответ: поскольку стандарт говорит, что вы этого не сделаете.

В стандарте С++ 12.8/9 (черновик N3242) говорится:

Неявно объявленный конструктор копирования для класса X будет иметь вид

  • X:: X (const X &)

если

  • каждый прямой или виртуальный базовый класс B из X имеет конструктор копирования, первый параметр которого имеет тип const B & или const volatile B &, и
  • для всех нестатических элементов данных X, которые имеют тип класса M (или его массив), каждый такой класс type имеет конструктор копирования, первый параметр которого имеет тип const M & или const volatile M &. [Примечание: 119]

В противном случае конструктор с неявным объявлением будет иметь вид

  • Х:: Х (Х &)

Примечание 119 гласит:

Это означает, что ссылочный параметр неявно объявленного конструктора копирования не может связываться с изменчивым значением lvalue; см. C.1.9.

В C.1.9 вы найдете:

Неявно объявленный конструктор копирования и неявно объявленный оператор назначения копирования не может сделать копия изменчивого значения. Например, в ISO C допустимо следующее:

struct X { int i; };
volatile struct X x1 = {0};
struct X x2(x1); // invalid C++
struct X x3;
x3 = x1; // also invalid C++

Обоснование: Несколько вариантов обсуждались подробно. Изменение параметра на летучую константу X & значительно усложнит создание эффективного кода для объектов класса. Обсуждение предоставления двух альтернативных подписей для этих неявно определенных операций вызывало безответную озабоченность по поводу создания двусмысленностей и усложнения правил, которые определяют формирование этих операторов в соответствии с базами и членами.

Ответ 2

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

X& X::operator =(const X& x){
   this.member = x.member;
   return *this;
}

Конструктор присваивания по умолчанию принимает тип аргумента как const X &, в котором const является низким уровнем const и не будет игнорируется как верхний уровень const.

Ваш код X b = a означает вызов конструктора по умолчанию. Но ваш аргумент a имеет тип volatile X (может быть преобразован в volatile X & и volatile const X &) не может быть преобразован до const X & неявно.

Итак, вы должны определить свой собственный конструктор назначения как

X& X::operator =(volatile const X&);

ИЗМЕНИТЬ
Меня шокирует то, что многие ребята думают, что при использовании оператора присваивания вызывается конструктор копирования (или вызов инициализации копирования). Может быть, назвать его оператором присваивания не является обычным явлением. Однако меня интересует, какой метод вызывается.

Вы можете обратиться к этому сообщению: Копировать конструкторы, операторы присваивания и безопасное присваивание исключений и Оператор присваивания по умолчанию


ИЗМЕНИТЬ
Я сделал ошибку ранее. X b = a - это всего лишь процесс инициализации. Никакое назначение не задействовано. Извините за мое сообщение об ошибке.