Все ли типы CopyConstructible MoveConstructible типов?

Согласно рабочему проекту N3337 (наиболее похожему на опубликованный стандарт ISOC++11) и cppreference.com, ответ - да.

N3337:

Таблица 21 - Требования CopyConstructible (в дополнение к MoveConstructible) [copyconstructible] [...]

cppreference.com:

Тип T удовлетворяет CopyConstructible, если

  • Тип T удовлетворяет MoveConstructible, и [...]

Но в соответствии с результатом компиляции main.cpp с gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4 и запуском a.out с цитируемыми операторами в Ubuntu 14.04.3 LTS, ответ - нет.

main.cpp:

#include <iostream>
#include <type_traits>

struct As
{
    As()=default;
    As(As&&)=delete;
    As(const As&)=default;
    As& operator=(As&&)=delete;
    As& operator=(const As&)=delete;
    ~As()=default;
};

int main()
{
    std::cout<<std::is_move_constructible<As>::value<<std::endl;
    std::cout<<std::is_copy_constructible<As>::value<<std::endl;

    return 0;
}

компилирование и запуск из терминала:

$ g++ -std=c++11 main.cpp
$ ./a.out

результат (выход):

0
1

Я что-то неправильно понял, или N3337 и cppreference.com не так, или gcc содержит ошибку?

3 ответа

Решение

std::is_copy_constructible<T> определяется точно std::is_constructible<T, const T&> т. е. он только проверяет, возможна ли конструкция из константного значения, он не проверяет все свойства концепции CopyConstructible.

Таким образом, ваш тест не показывает то, что вы думаете, что показывает. Ваш тип не является типом CopyConstructible, потому что он не соответствует некоторым другим требованиям.

Что касается оригинального вопроса, да. Поскольку все типы CopyConstructible должны соответствовать требованиям для MoveConstructible, все они являются типами MoveConstructible. MoveConstructible не требует перемещения чего-либо, возможно только создание из значений rvalue, а все типы CopyConstructible могут быть созданы из значений rvalue (даже если они могут сделать глубокое копирование, а не перемещение).

Вы можете создавать извращенные типы, которые могут быть скопированы из l-значений, но не из r-значений, или могут быть скопированы из const-значений l, но не не-const-значений l и других мерзостей. Такие типы не являются CopyConstructible и плохо работают со стандартной библиотекой C++. Есть очень мало веских причин когда-либо создавать извращенные типы, подобные этому.

Ваш пример несколько вводит вас в заблуждение.

As(As&&)=delete;

Удаляя конструктор перемещения, вы запрещаете создавать As с As&&даже если вместо этого можно вызвать конструктор копирования, поскольку он принимает ссылку на const.

Пример, который отображает поведение, которое вы ищете, это:

struct As
{
    As()=default;
    As(const As&)=default;
    As& operator=(As&&)=delete;
    As& operator=(const As&)=delete;
    ~As()=default;
};

Я только что удалил удаление конструктора перемещения. As не будет иметь неявно объявленного конструктора перемещения, потому что у него есть куча других объявленных пользователем специальных функций *. Если вы запустите свои тесты на этом примере, вы увидите, что класс можно конструировать с помощью Move, даже если у него нет конструктора Move.

Live Demo


* В частности, конструктор перемещения не будет объявлен неявно, если существует пользовательский конструктор копирования, оператор копирования, оператор назначения перемещения или деструктор.

is_copy_constructible не требует, чтобы тип был подвижным. Когда это говорит

Требования CopyConstructible (в дополнение к MoveConstructible) [copyconstructible]

Это означает, что, чтобы быть CopyConstructible, класс должен удовлетворять требованиям MoveConstructible, которые

T u = rv;       u is equivalent to the value of rv before the construction
T(rv)           T(rv) is equivalent to the value of rv before the construction

rv’s state is unspecified. [ Note: rv must still meet the requirements of the
library component that is using it. The operations listed in those requirements
must work as specified whether rv has been moved from or not. — end note ]

В дополнение к [copyconstructible]

T u = v;        the value of v is unchanged and is equivalent to u
T(v)            the value of v is unchanged and is equivalent to T(v)

Причина std::is_move_constructible<As>::value Значение false означает, что у вас есть удаленный конструктор перемещений, который запрещает построение перемещений. Наличие не удаленного конструктора перемещения и удовлетворение [moveconstructible] необходимы для того, чтобы он был истинным.

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