Предоставляет ли С++ 11 вектор <const T>?
Требования к контейнеру изменились с С++ 03 на С++ 11. Хотя С++ 03 имеет общие требования (например, конструктивность копирования и назначение для вектора), C ++ 11 определяет мелкозернистые требования к каждой операции с контейнером (раздел 23.2).
В результате вы можете, например, сохраните тип, который можно копировать, но не назначать - например, структуру с константным элементом - в векторе, пока вы выполняете только определенные операции, которые не требуют назначения (конструкция и push_back
являются такими операциями; insert
не является).
Мне интересно: это означает, что теперь стандарт позволяет vector<const T>
? Я не вижу причин, по которым это не должно быть - const T
, как структура с членом-константой, является типом, который является конструктивным, но не назначаемым, но я, возможно, что-то пропустил.
(Часть того, что заставляет меня думать, что я, возможно, что-то пропустил, состоит в том, что магистраль gcc сбой и ожоги, если вы пытаетесь создать экземпляр vector<const T>
, но это нормально с vector<T>
, где T имеет член const).
Ответы
Ответ 1
Нет, я считаю, что требования к распределителю говорят, что T может быть "неконстантным, не ссылочным типом объекта".
Вы не сможете многое сделать с вектором постоянных объектов. И const vector<T>
был бы почти таким же.
Спустя много лет этот быстрый и грязный ответ все еще, кажется, привлекает комментарии и голоса. Не всегда наверху. :-)
Итак, чтобы добавить некоторые правильные ссылки:
Для стандарта С++ 03, который у меня есть на бумаге, в Таблице 31 в разделе [lib.allocator.requirements] сказано:
T, U any type
Не то чтобы любой тип на самом деле работал.
Итак, следующий стандарт, С++ 11, говорит в закрытом черновике в [allocator.requirements] и теперь в таблице 27:
T, U, C any non-const, non-reference object type
что очень близко к тому, что я изначально написал выше по памяти. Это также то, о чем был вопрос.
Однако в С++ 14 (черновик N4296) в таблице 27 теперь говорится:
T, U, C any non-const object type
Возможно, потому что ссылка, возможно, не тип объекта в конце концов?
И теперь в С++ 17 (проект N4659) это Таблица 30, которая говорит:
T, U, C any cv-unqualified object type (6.9)
Так что не только const
исключается, но и volatile
. Вероятно, старые новости в любом случае, и просто разъяснение.
Пожалуйста, также посмотрите информацию из первых рук Говарда Хиннанта, в настоящее время прямо ниже.
Ответ 2
Обновление
Под принятым (и правильным) ответом я прокомментировал в 2011 году:
Нижняя строка: мы не создали контейнеры для хранения const T
. Хотя я и сделал подумайте. И мы очень приблизились к авария. Насколько я знаю, текущая точка пара перегруженных address
функций-членов по умолчанию распределитель: Когда T
есть const
, эти две перегрузки имеют одинаковые подпись. Простым способом исправить это было бы специализация std::allocator<const T>
и удалите одну из перегрузок.
С предстоящим проектом С++ 17 мне кажется, что мы теперь узаконили vector<const T>
, и я также считаю, что мы сделали это случайно.: -)
P0174R0 удаляет перегрузки address
с std::allocator<T>
. P0174R0 не упоминает о поддержке std::allocator<const T>
как части его обоснования.
Коррекция
В комментариях ниже T.C. правильно отмечает, что перегрузки address
устарели, а не удалены. Виноват. Устаревшие члены не отображаются в 20.10.9, где std::allocator
определен, но вместо этого отнесены к разделу D.9. Я забыл просканировать главу D для этой возможности, когда я разместил это.
Спасибо T.C. для исправления. Я предполагал удалить этот вводящий в заблуждение ответ, но, возможно, лучше оставить его с этой коррекцией, чтобы, возможно, это заставило кого-то другого неправильно интерпретировать спецификацию так же, как и я.
Ответ 3
Несмотря на то, что у нас уже есть очень хорошие ответы на это, я решил внести более практичный ответ, чтобы показать, что может и что не может быть сделано.
Так что это не работает:
vector<const T> vec;
Просто прочитайте другие ответы, чтобы понять, почему. И, как вы, возможно, догадались, это тоже не сработает:
vector<const shared_ptr<T>> vec;
T
больше не const
, но vector
удерживает shared_ptr
s, а не T
s.
С другой стороны, это работает:
vector<const T *> vec;
vector<T const *> vec; // the same as above
Но в этом случае const является объектом, на который указывает объект, а не сам указатель (что и хранит вектор). Это будет эквивалентно:
vector<shared_ptr<const T>> vec;
Это нормально.
Но если мы поместим const
в конец выражения, теперь он превратит указатель в const
, поэтому следующее не будет компилироваться:
vector<T * const> vec;
Немного запутанный, я согласен, но вы привыкаете к нему.
Ответ 4
В дополнение к другим ответам, другой подход заключается в использовании:
vector<unique_ptr<const T>> vec;
Если это так, вы хотите обеспечить, чтобы только vec
владела своими товарами. Или, если вы хотите динамически перемещать элементы в vec
и в какой-то момент их вывести.
Как указано, семантика указателя const
может вводить в заблуждение, но shared_ptr
и unique_ptr
- нет. const unique_ptr<T>
является указателем константы, а unique_ptr<const T>
является константой, как и следовало ожидать.