Почему string_view вместо обобщенного container_view <T>?

Я нашел string_view из нового стандарта С++ 17 немного избыточным.

У нас есть довольно многословная коллекция простых механизмов для передачи данных вызываемому без значительных издержек, и теперь есть одна другая, которая также специфична только для одного тип контейнера.

Я не понимаю, почему это оборудование предназначено только для струнных, а не для некоторых других типов. Один разумный ответ заключается в том, что у нас уже есть такие решения. Например, в С++ 17 и выше представление string_view объясняется как observer_ptr<T> (or T*) for string.

Просьба указать аргументы в отношении более общего контейнера-просмотра, в отличие от string_view, представленного С++ 17.

Ответ 1

Обобщенный container_view более правильно называется диапазоном. У нас есть TS-маршрут, полностью посвященный концепциям диапазона.

Теперь у нас есть string_view как отдельный тип, потому что у него есть специализированный, специфичный для строки интерфейс для соответствия basic_string связанного с строкой интерфейса. Или, по крайней мере, для соответствия интерфейсам const/non-allocating.

Обратите внимание, что container_view или то, что вы его вызывали, не сможет удалить его соединение с контейнером, который его создал. Или, по крайней мере, не без оплаты служебных данных стирания на каждом доступе/операции.

В отличие от этого, string_view основан на const char* и целых числах. Этот класс не волнует, откуда взялась строка; он обеспечивает представление в смежном массиве символов независимо от того, кто его владеет. Он может это сделать, потому что он знает, что источник является непрерывным массивом и поэтому использует указатели как ядро ​​его итератора.

Вы не можете сделать это для произвольных контейнеров. У вашего container_view<vector> будут разные итераторы от container_view<list> или что угодно. Это должно было бы. Это означает, что если вы берете container_view как параметр функции, вы должны либо выбрать конкретный используемый контейнер (заставляя пользователя предоставлять именно этот тип контейнера), сделать вашу функцию шаблоном или использовать диапазон итераторов с стиранием типа ( таким образом, медленнее).

Есть также предложения post-С++ 17 для типов GSL span и string_span. Первый представляет собой модифицируемое "представление" (возможно многомерного) смежного массива. Последний представляет собой изменяемый "вид" непрерывной строки.

Ответ 2

string_view предлагает более простой указатель на строку. Вы должны рассматривать это как нечто большее, чем простой указатель, не являющийся владельцем: если бы все это было, string_view не мог позволить вам "срезать" части строки и применять к ней операции (пока еще вид, таким образом, не приносит стоимость копии):

char *s = "welcome to stackoverflow";
auto s = std::string_view{s + 8, 2}; // a view on "to"
// you can then apply many operations on this view, that wouldn't make sense more on your general non_owning<T>:
s.remove_prefix(std::min(s.find_first_not_of(" "), s.size()));
// it also "inherits" (copies the API) a lot directly from std::basic_string
auto view2 = s.substr(3, 4); // a generic non-owning ptr would copy here, instead of giving you a new view