Можно ли определить конструкторы копирования контейнеров как удаленные для не копируемых типов значений? - PullRequest
0 голосов
/ 08 ноября 2018

Если у нас есть контейнер с типом значения, не подлежащего копированию , такой класс контейнеров все еще определяет конструктор копирования , просто он может не вызываться.

using T = std::vector<std::unique_ptr<int>>;
std::cout << std::is_copy_constructible_v<T>; // prints out "1" (libstdc++)

Это может вызвать «скрытые» проблемы, такие как обсуждаемая здесь: Нужно ли Visual Studio 2017 явное объявление конструктора перемещения? .

Мой вопрос заключается в том, могут ли реализации Стандартной библиотеки определить такой конструктор копирования как условно удаленный, а именно удаленный в случае не копируемых типов значений . Это имело бы смысл для меня (по крайней мере, пока есть понятия C ++). Будет ли такая реализация соответствовать стандарту?

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Это математически невозможно с тех пор, как vector получил поддержку неполного типа:

struct E {
    std::vector<E> e;
};

E копируется, если std::vector<E> копируется, а std::vector<E> копируется, если E копируется. Черепахи все время вниз.

Даже до этого, поскольку construct распределителя может искажать аргументы конструктора так, как он считает нужным, и у контейнера нет способа определить, является ли что-то «конструктор-распределитель», условное удаление конструктора копирования потребовало бы некоторого серьезного проектные работы. Неполная поддержка типа просто положить гроб в гроб.

0 голосов
/ 08 ноября 2018

Как Т.С. говорит, что это может быть даже неосуществимо, но если бы это было так, я считаю, что раздел [member.functions] p2 в разделе Соответствующие реализации не позволяет этого:

Для невиртуальной функции-члена, описанной в стандартной библиотеке C ++, реализация может объявить другой набор сигнатур функций-членов при условии, что любой вызов функции-члена, который выберет перегрузку из набора объявлений, описанного в этом Документ ведет себя так, как будто эта перегрузка была выбрана. [Примечание: Например, реализация может добавлять параметры со значениями по умолчанию или заменять функцию-член аргументами по умолчанию с двумя или более функциями-членами с эквивалентным поведением, или добавлять дополнительные подписи для имени функции-члена. - конец примечания ]

0 голосов
/ 08 ноября 2018

Для краткого ответа: нет. Если мы посмотрим на текущую спецификацию (начиная с c ++ 17) std :: vector, у нас будет следующая подпись и описание:

vector(const vector& other);

Копировать конструктор. Создает контейнер с копией содержимого другого. Если alloc не предоставлен, allocator получается как будто путем вызова std :: allocator_traits :: select_on_container_copy_construction (other.get_allocator ()).

Конструктор копирования имеет обычную каноническую подпись, и в описании не указано никаких условий SFINAE, поэтому соответствующая реализация не должна налагать более строгие требования, такие как условное удаление. Тем не менее, ошибка экземпляра произойдет, если будет предпринят явный или неявный вызов ctor-копии vector<unique_ptr<T>>, поскольку описание подразумевает поэлементное копирование. Таким образом, vector<unique_ptr<T>> не удовлетворяет требованию CopyConstructible, что очень похоже на наличие конструктора удаленной копии.

Насколько я знаю, нет синтаксической поддержки условного удаления, но условия SFINAE и скоро появившиеся ограничения могут обеспечить выборочное разрешение перегрузки. Я все еще настоятельно рекомендую не использовать их в специальных операциях. Специальные операции должны быть определены с использованием их обычной канонической подписи.

...