Обнаружение непрерывного итератора

C ++ 17 представил концепцию ContiguousIterator http://en.cppreference.com/w/cpp/iterator. Однако не похоже, что есть планы, чтобы contiguous_iterator_tag (точно так же, как у нас сейчас random_access_iterator_tag) сообщил std::iterator_traits<It>::iterator_category.

Почему отсутствует contiguous_iterator_tag?

Есть ли традиционный протокол для определения смежности итератора? Или тест на время компиляции?

Ранее я упоминал, что для контейнеров, если есть член .data(), который преобразуется в указатель на тип ::value, и есть член .size(), конвертируемый в различия указателей, тогда следует предполагать, что контейнер является смежным, но Я не могу тянуть аналогичную фичу итераторов.

Одним из решений может быть также data функция для смежных итераторов.

Конечно, концепция смежности работает, если &(it[n]) == (&(*it)) + n, для всех n, но это нельзя проверить во время компиляции.


РЕДАКТИРОВАТЬ: я нашел это видео, в котором это рассматривается в более широком контексте концепций C ++. CppCon 2016: Создание и Расширение иерархии итераторов в современном многоядерном мире Патрика Недзельски. В решении используются концепции (Lite), но в конечном итоге идея состоит в том, что смежные итераторы должны реализовывать функцию pointer_from (такую ​​же, как моя функция data(...)).

Вывод состоит в том, что концепции помогут формализовать теорию, но они не являются волшебством в том смысле, что кто-то где-то определит новые специально названные функции над смежными итераторами. Обсуждение обобщается на сегментированные итераторы (с соответствующими функциями segment и local), к сожалению, в нем ничего не говорится о полосовых указателях.


ИЗМЕНИТЬ 2020:

В стандарте теперь есть

struct contiguous_iterator_tag: public random_access_iterator_tag { };

https://en.cppreference.com/w/cpp/iterator/iterator_tags


person alfC    schedule 17.03.2017    source источник
comment
Почему отсутствует contiguous_iterator_tag? ← потому что он незаметно нарушит код до C ++ 17, предполагавший, что std::vector::iterator является итератором с произвольным доступом?   -  person kennytm    schedule 17.03.2017
comment
@kennytm, Тонкая причина. Но если черты используются правильно (я думаю), можно сделать его обратно совместимым (например, если random_access_iterator получен из contiguous_iterator_tag). Было бы прискорбно, если бы разрыв произошел только из-за неправильного использования трейта.   -  person alfC    schedule 17.03.2017
comment
Ситуация не выглядит многообещающей. Я думаю, что возможной идеей было бы предоставить член .data() или data(ContiguousIterator it) функцию для всех смежных итераторов, это аналогично контейнерам, которые в настоящее время имеют член .data(), когда они смежные.   -  person alfC    schedule 22.03.2017
comment
Что ж, чего они ожидали от специального полиморфизма? Одним из мотивов C ++ было избегать его. Вся эта штука с iterator_tag должна быть изгнана на произвол судьбы.   -  person Jive Dadson    schedule 05.12.2017
comment
@JiveDadson Я частично согласен по следующей причине. Я пришел к выводу, что теги - плохая замена тому, что должно быть реализовано с помощью обнаружения операторов. Например, если есть оператор ++, то это прямой итератор, если есть оператор + =, то это произвольный доступ, если есть функция данных, то это непрерывный итератор и т. Д.   -  person alfC    schedule 05.12.2017


Ответы (1)


Оригинальный ответ

Обоснование приводится в N4284. , который является принятой версией предложения непрерывных итераторов:

В этой статье термин непрерывный итератор вводится как уточнение итератора с произвольным доступом без введения соответствующего contiguous_iterator_tag, который, как было обнаружено, нарушает код во время обсуждений Иссакуа статьи Невина Либера «Смежные итераторы N3884: уточнение итераторов с произвольным доступом».

Некоторый код был сломан, потому что предполагалось, что std::random_access_iterator не может быть уточнен, и имел явные проверки против него. По сути, он сломал плохой код, который не полагался на полиморфизм для проверки категорий итераторов, но, тем не менее, он сломал код, поэтому std::contiguous_iterator_tag был удален из предложения.

Кроме того, возникла дополнительная проблема с классами, подобными std::reverse_iterator: обратное смежное Итератор не может быть непрерывным итератором, но может быть обычным итератором с произвольным доступом. Эту проблему можно было бы решить для std::reverse_iterator, но большее количество пользовательских оболочек итераторов, которые дополняют итератор при копировании его категории итератора, либо лгут, либо перестают работать правильно (например, адаптеры итератора Boost).

Обновление C ++ 20

Поскольку мой первоначальный ответ выше, std::contiguous_iterator_tag был возвращен в Ranges TS, а затем принят в C ++ 20. Чтобы избежать проблем, упомянутых выше, поведение std::iterator_traits<T>::iterator_category не было изменено. Вместо этого пользовательские специализации std::iterator_traits теперь могут определять дополнительный iterator_concept псевдоним типа члена, который разрешено использовать псевдоним std::contiguous_iterator_tag или предыдущие теги итератора. Стандартные компоненты были обновлены соответствующим образом, чтобы отмечать указатели и соответствующие итераторы непрерывными итераторами.

Стандарт определяет ITER_CONCEPT (Iter) только для описания, который, учитывая тип итератора Iter, будет иметь псевдоним std::iterator_traits<Iter>::iterator_concept, если он существует, и std::iterator_traits<Iter>::iterator_category в противном случае. Не существует эквивалентного стандартного признака типа, обращенного к пользователю, но ITER_CONCEPT используется новыми концепциями итератора. Это сильный намек на то, что вы должны использовать эти концепции итераторов вместо отправки тегов в старом стиле для реализации новых функций, поведение которых зависит от категории итератора. При этом упомянутые концепции можно использовать как логические признаки, поэтому вы можете просто проверить, что итератор является непрерывным итератором, следующим образом:

static_assert(std::contiguous_iterator<Iter>);

std::contiguous_iterator, таким образом, является концепцией C ++ 20, которую вы должны использовать для обнаружения этого данный итератор является итератором с произвольным доступом (у него также есть аналог диапазонов: _16 _ ). Стоит отметить, что std::contiguous_iterator имеет несколько дополнительных ограничений помимо требования, чтобы ITER_CONCEPT соответствовал std::contiguous_iterator_tag: в первую очередь это требует _ 19_, чтобы быть допустимым выражением, возвращающим необработанный тип указателя. std::to_address - это небольшая служебная функция, предназначенная для того, чтобы избежать нескольких ошибок, которые могут возникнуть при попытке получить адрес, на который указывает непрерывный итератор - вы можете узнать больше о проблемах, которые она решает, в Полезные указатели для ContiguousIterator.

person Morwenn    schedule 17.03.2017
comment
Отличное объяснение. Это печальный сценарий из всех. Думаю, ContiguousIterator нельзя использовать программно, по крайней мере, для std::vector. - person alfC; 17.03.2017
comment
@alfC Как есть, ContiguousIterator - это не более чем стандартный термин, который помогает собрать различные свойства и гарантии итераторов смежных стандартных коллекций. К несчастью. std::contiguous_iterator_tag было бы здорово, но должно было быть там с самого начала: / - person Morwenn; 17.03.2017
comment
Мы можем надеяться, что ситуация улучшится, когда Concepts TS войдет в стандарт. - person Oktalist; 17.03.2017
comment
@Oktalist, у вас есть конкретное представление о том, как Concepts поможет? В конце концов, некоторые должны знать, что определенный итератор является смежным и для этого требуется какой-то протокол. Протокол уже существует, но кажется, что его невозможно расширить за счет обратной совместимости. - person alfC; 20.03.2017
comment
@alfC Нет. На самом деле я должен был сказать Ranges TS, который зависит от Concepts, но на самом деле сохраняет тот же старый протокол. Новый протокол с нуля был бы продвижением вперед ИМХО, оставив старый для BC. Диапазоны v3 вводят концепцию ContiguousRange, но я не уверен, как она работает. - person Oktalist; 21.03.2017
comment
@Oktalist, спасибо, я знаю, что в этих статьях упоминается взлом кода, но я не вижу, какой именно код взломан. Я согласен с тем, что в такой ситуации, похоже, нам следует начать с нуля некоторую категорию концепций и повторную реализацию iterator_traits_v2. Кроме того, знание того, что итератор является смежным, на самом деле является первым шагом, необходимо также знать шаги (обычно 1). Таким образом, параллельный trait может выполнять эту работу template<class It> class iterator_stride{} (специализированный только для смежных итераторов) с членом value (или value()). - person alfC; 21.03.2017
comment
@Oktalist Концепция range-v3 ContiguousRange полностью обходит проблему идентификации смежных итераторов, определяя ContiguousRange как RandomAccessRange, ссылочный тип которого является истинной ссылкой и для которого точка настройки ranges::data возвращает указатель, разыменованный на тот же ссылочный тип. Единственное использование прямо сейчас - это конструктор преобразования для span, а ContiguousRange - поскольку он не предполагает, что тип итератора является смежным - полезно только в том случае, если диапазон также моделирует SizedRange. - person Casey; 04.04.2017
comment
youtu.be/N80hpts1SSk?t=2421 В решении используются концепции (Lite), но в конце идея состоит в том, что смежные итераторы должны реализовывать функцию pointer_from (такую ​​же, как моя функция data(...)). - person alfC; 05.05.2017
comment
@Morwenn, спасибо за постоянные обновления. Это идет в правильном направлении. Далее, полосатые итераторы. Как мне обнаружить полосатые итераторы? :) - person alfC; 12.06.2019
comment
@alfC В прошлом предлагались сегментированные и иерархические итераторы, но они были сочтены слишком сложными для работы. Строгие вещи обычно возникают в обсуждениях SIMD и параллельных алгоритмов, но я не думаю, что есть что-либо, предлагающее какие-то ступенчатые итераторы. В Range-v3 есть полосатое представление, но оно не предлагалось для C ++ 20. Пока что единственным компонентом стандартной библиотеки с последовательным разделением является std::[g]slice_array, но, похоже, он не предоставляет итераторов. - person Morwenn; 12.06.2019
comment
@Morwenn, еще один пример последовательного итератора естественно появляется в области многомерных массивов (когда массивы реализованы в непрерывной памяти). Например, gitlab.com/correaa/boost-multi. - person alfC; 12.06.2019
comment
Для этого был обновлен стандарт: en.cppreference.com/w/cpp/iterator/ iterator_tags. Я думаю, что это может быть доступно iterator_concept (вместо iterator_category), чтобы не нарушать совместимость, как вы сказали. В перспективе, праздновать или плакать, я не знаю. Я говорю это потому, что думаю, что эти теги не так важны, как соответствующие функции-черты, которые делают теги полезными (например, в этом случае он должен сопровождаться чем-то вроде static std::iterator_traits<It>::data(It), чтобы сделать его полезным. Или потенциальные концепции между Случайные и смежные. - person alfC; 19.11.2020
comment
@alfC Спасибо, я обновил ответ (надеюсь, точным) сводкой того, что предлагает C ++ 20 по отношению к непрерывным итераторам. - person Morwenn; 19.11.2020
comment
Ожидается ли, что программист class MyContigIterator взломает open namespace std, чтобы записать необходимую перегрузку std::to_address(MyContigIterator)? Эта перегрузка не возникает просто волшебным образом, верно? (Он может иметь определение по умолчанию, например, в терминах it.operator->(), но стандартный std::to_address не имеет AFAICT по умолчанию.) - person Quuxplusone; 14.01.2021
comment
@Quuxplusone «Если выражение std::pointer_traits<Ptr>::to_address(p) правильно сформировано, возвращает результат этого выражения. В противном случае возвращает std::to_address(p.operator->()) », поэтому я полагаю, что стандартный шаблон функции работает нормально, если ваш итератор предоставляет operator->. На самом деле я не уверен. Это просто странно. - person Morwenn; 14.01.2021