Ответ 1
Конструктор копирования std::pair
объявляется следующим образом:
pair(const pair&) = default;
Объявив этот конструктор копирования для movable
:
movable(movable&) = delete;
вы запрещаете неявное создание movable(const movable&)
(поэтому он даже не удаляется, просто нет такого конструктора), таким образом, это единственный созданный вами конструктор. Но конструктор std::pair
copy требует, чтобы конструктор копирования его членов принимал const-ссылку, поэтому вы получаете ошибку компиляции.
Если вы добавите это:
movable(movable const&) = delete;
или (лучше) просто удалите объявление movable(movable&) = delete;
, теперь у вас есть конструктор movable(movable const&)
, и поскольку он удален, конструктор копирования std::pair
также удаляется.
Обновить. Рассмотрим более простой пример, демонстрирующий ту же проблему. Это не компилируется:
template <typename T>
struct holder {
T t;
// will compile if you comment the next line
holder(holder const&) = default;
// adding or removing move constructor changes nothing WRT compile errors
// holder(holder&&) = default;
};
struct movable {
movable() {}
movable(movable&&) = default;
// will also compile if you uncomment the next line
//movable(movable const&) = delete;
movable(movable&) = delete;
};
holder<movable> h{movable()};
Он будет компилироваться, если вы прокомментируете конструктор копирования holder
, потому что это то, как работает неявное создание конструктора копии ([class.copy]/8
:
Неявно объявленный конструктор копирования для класса X будет иметь вид
X::X(const X&)
если каждый потенциально сконструированный подобъект типа класса
M
(или его массив) имеет конструктор копирования, первый параметр которого имеет типconst M&
илиconst volatile M&
. В противном случае конструктор с неявным объявлением будет иметь вид
X::X(X&)
То есть, когда вы закомментируете объявление holder(holder const&) = default;
, неявно объявленный конструктор копирования holder
будет иметь форму holder(holder&)
. Но если вы этого не сделаете, конструктор T
copy примет const T&
(или const volatile T&
), потому что это то, что будет вызываться в процедуре поэтапной копии, описанной в [class.copy]/15
.
И если holder
имеет конструктор перемещения, это еще проще - если вы закомментируете holder(holder const&) = default;
, неявно объявленный конструктор копирования holder
будет просто удален.