Разница между удаленным конструктором и неявным необъявленным конструктором заключается в том, что удаленный конструктор участвует в разрешении перегрузки, тогда как несуществующий конструктор не участвует в разрешении перегрузки.
Пример:
Этот класс является конструируемым по умолчанию. Компилятор неявно объявляет для него конструктор по умолчанию.
struct A
{
template <class ...T>
A(T...) {}
};
int main()
{
A a; // ok
}
Если компилятор объявил для него конструктор по умолчанию, и если этот конструктор по умолчанию был определен как удаленный, то A
не будет конструируемым по умолчанию. Это может быть смоделировано с:
struct A
{
A() = delete; // pretend the compiler implicitly declared and defined this
template <class ...T>
A(T...) {}
};
int main()
{
A a;
}
error: call to deleted constructor of 'A'
A a;
^
Аналогичные проблемы возникают с конструктором перемещения. Если компилятор решит неявно объявить его и определить как удаленный, то нельзя создать такой класс из значения r, даже если у него есть жизнеспособный конструктор копирования:
#include <type_traits>
struct A
{
A();
A(const A&);
A(A&&) = delete; // pretend compiler declared and defined
};
int main()
{
A a = std::declval<A>();
}
error: call to deleted constructor of 'A'
A a = std::declval<A>();
^ ~~~~~~~~~~~~~~~~~
Но если компилятор не неявно не объявляет удаленный конструктор перемещения, то все просто работает:
#include <type_traits>
struct A
{
A();
A(const A&);
};
int main()
{
A a = std::declval<A>(); // ok
}
Действительно, если бы компилятор действительно неявно объявил удаленный конструктор перемещения для A
, при перекомпиляции в C ++ 11 было бы очень много сломанного кода C ++ 98/03! : -)