Почему тип CopyConstructible также должен быть MoveConstructible?
Как указано в cppreference, требование для типа T быть CopyConstructible состоит в том, что он также должен быть MoveConstructible.
Проект концепции STL CopyConstructible содержит:
template <class T> concept CopyConstructible = std::MoveConstructible<T> && std::Constructible<T, T&> && std::ConvertibleTo<T&, T> && std::Constructible<T, const T&> && std::ConvertibleTo<const T&, T> && std::Constructible<T, const T> && std::ConvertibleTo<const T, T>;
который поддерживает названный оператор требования. Учитывая вышеприведенное определение, такой тип:
struct HaveCopy {
HaveCopy(const HaveCopy&) = default;
HaveCopy(HaveCopy&&) = delete;
HaveCopy& operator= (const HaveCopy&) = default;
HaveCopy& operator= (HaveCopy&&) = delete;
};
не проходит простой тест:
static_assert(std::CopyConstructible<HaveCopy>);
тогда как проходит старое:
static_assert(std::is_copy_constructible<HaveCopy>::value);
Итак, вопрос почему? Каково намерение комитета по стандартам в этом вопросе? HaveCopy не может быть перемещаемым, но, по моему мнению, является в значительной степени копируемым std::is_copy_constructible<>
согласен со мной
Такое же поведение также наследуется концепцией Copyable, которая:
template <class T> concept Copyable = std::CopyConstructible<T> && std::Movable<T> && std::Assignable<T&, const T&>;
Итак, тест:
static_assert(std::Copyable<HaveCopy>);
потерпит неудачу также. На этот раз отказ удваивается. И то и другое CopyConstrucible<>
а также Movable<>
не согласен с тем, что HaveCopy можно копировать.
Обсуждение здесь как-то похоже, но не отвечает почему. Зачем нам это поведение? Исключает ли этот вид проверки допустимые типы копируемых конструктивов или HaveCopy вообще не копируется конструктивно? Последнее кажется мне действительно странным, если это правда.
Какие-нибудь мысли?
1 ответ
Да, CopyConstructible
понятие совершенно иное, чем черта типа std::is_copy_constructible
, Вы сосредотачиваетесь на конструкторе перемещения, но есть также много других случаев, которые следует рассмотреть. Как вы думаете, этот тип должен быть CopyConstructible?
struct A {
A(A&) = delete;
A(A const&);
};
Как насчет этого?
struct B {
explicit B(B const&);
};
Дело в том, что существует бесконечное множество комбинаций конструкторов, которые вы можете написать. Это не значит, что они все значимы или заслуживают поддержки. Наличие типа с конструктором копирования, но с удаленным конструктором перемещения просто не имеет смысла.
Concepts - это не просто проверка синтаксиса, но и обеспечение соблюдения семантических требований, требующих значимых типов, которые в итоге становятся проще в кодировании. Если вы просто проверите is_copy_constructible
все, что вы позволяете себе делать, это явно конструировать ваш тип из константного значения. Пишу T x = y;
, даже если y
это const T
уже вне этой области! Это может быть буквально то, что означает copy constructible, но это гораздо менее значимо, чем более широкое "Я могу построить T
из T
" - что намного ближе к тому, о чем мы думаем, когда думаем о копировании. Вот что такое концепция CopyConstructible
дает нам.
Когда вы просматриваете библиотеку, есть и другие концепции, которые требуют большего (синтаксически и семантически), чем может предложить прямой перевод их названия. EqualityComparableWith<T,U>
не просто проверить, что я могу написать t == u
но также u == t
, t != u
, а также u != t
также. StrictTotallyOrdered
не только проверяет операторы заказа, но и проверяет ==
, Наличие связного целого важно.