Почему тип 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 не только проверяет операторы заказа, но и проверяет ==, Наличие связного целого важно.

Другие вопросы по тегам