Рассмотрим проблему подробнее.
class A {
private:
int aa;
int ab;
public:
A()
: aa(0), ab(0) {} // (4) note: candidate constructor not viable: requires
// 0 arguments, but 1 was provided
A(int a)
: aa(a), ab(0) {} // (2) note: candidate constructor not viable: no known
// conversion from 'A' to 'int' for 1st argument
A(A& obj); // (3) note: andidate constructor not viable: expects an l-value
// for 1st argument
void Show() { cout << "Var1: " << aa << endl << "Var2: " << ab << endl; }
};
int main() {
A obj = 5; // (1) error: cannot bind non-const lvalue reference of type ‘A&’
// to an rvalue of type ‘A’
obj.Show();
return 0;
}
Стандарт обязывает понимать
A(A& obj);
как user-defined конструктор копирования. Поэтому, конструктор копирования
T::T(const T&)
не будет объявлен по-умолчанию компилятором. Со стандарта C++11 предоставляется возможность заставить компилятор генерировать неявно-объявленный конструктор копирования ключевым словом default
A(A& obj) = default;
Неявно объявленный конструктор копирования по-умолчанию имеет сигнатуру
T::T(const T&)
но лишь в случае, когда все базовые классы T имеют конструкторы копирования с параметрами const B& или const volatile B&, и когда все не статические данные-члены класса T имеют конструкторы копирования с параметрами const M& или const volatile M&.
В ином случае, неявно объявленный конструктор копирования имеет сигнатуру
T::T(T&)
В данном случае, конструктор копирования A(A& obj) является тривиальным с сигнатурой сгенерированного неявно-определённого конструктора копирования T::T(T&).
Тривиальное копирование практически аналогично
std::memmove
В строке ошибки компиляции происходит следующее:
1) оператор = в строке с ошибкой компиляции не является инициализирующим, поскольку литерал 5 является (rvalue, нельзя взять адрес) const int. Для исполнения операции присваивания компилятор сначала конструирует A(5);
...
A(int a) : aa(a), ab(0) {
cout << "Copy ctor with 1 parameter is called " << endl;
}
…
int main() {
…
Вывод:
Copy ctor with 1 parameter is called
Var1: 5
Var2: 0
2) операция присваивания имеет дело с A obj = A (5):
Справа от оператора присваивания находится временный rvalue типа class A.
Данное присваивание является инициализирующим, что делает его эквивалентным A obj(A(5));
Для данной операции необходим конструктор с сигнатурой T::T(T&&)
Это - конструктор перемещения, и он в классе A отсутствует, поскольку неявное определение конструктора перемещения в классе требует отсутствия user-defined конструкторов копирования, оператора = копирования, оператора = присваивания, деструктора. В нашем случае, у нас имеется user-defined A(A& obj);
Учитывая вышесказанное, для исправления ошибки компиляции можно либо удалить строку
A(A& obj); ,
что приведёт к неявному определению компилятором тривиальных конструкторов копирования и перемещения, либо добавить ещё в объявление класса A строку
A(A&& obj);
С точки зрения стандарта С++11 и выше, можно утверждать, что выражения A(A& obj); и A(A&& obj); соответственно эквивалентны A(A& obj) = default; и A(A&& obj) = default;