LINUX.ORG.RU

Заколхозить итератор

 


0

4

Привет. Нужен итератор для своего класса (как писать по старинке в целом представляю - сделать нужные тайпдефы), смотрю в справочник, куча всего стала deprecated, включая старые требования к итераторам (внимание на LegacyIterator).

std::iterator_traits is the type trait class that provides uniform interface to the properties of LegacyIterator types. 

Во всем этом замешаны и новомодные концепты. Не хочется писать какое-то легаси г, как сейчас станет правильным? Сделать член-тип таг (random_access_iterator_tag, например), а весь этот iterator_traits интерфейс не нужен будет? Ну а чего они его легаси обзывают.

★★

Я с концептами не разбирался еще, может там нужно унаследоваться от него?

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

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

anonymous
()

Ты перепутал legacy с deprecated?

anonymous
()

Зависит от требований.

struct iterator {} с операторами ++, -> и *.

И в довесок begin(iterator) и end(iterator)

invy ★★★★★
()
Ответ на: комментарий от invy

Ну это естественно, но без тайпдефов не будут работать стд алгоритмы. Кажется, я начиная подозревать в чем тут дело - нам всем хотят рекомендовать пользоваться стд::ranges вместо стд::алгоритмов, а для них все это хозяйство (iterator_traits и смежное не нужно). Проверить пока затруднительно - в стд::ranges не все завезли, а проверять с версией из буста лень.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Что-то цпп стал слишком часто и радикально меняться.

После окончания университетов многие 2 + 2 рассчитывают с использованием тройного интеграла.

Это и есть современный C++

Владимир

anonymous
()

Пиши враппер внутрь можешь депрекейтед кода засунуть если будет острая нужда поменяешь реализацию внутри оставив свой интерфейс неизменным, профит.

anonymous
()
Ответ на: комментарий от pavlick

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

anonymous
()
Ответ на: комментарий от pavlick

https://www.boost.org/doc/libs/1_74_0/doc/html/stl_interfaces.html#boost_stlinterfaces.introduction.a_quick_example

Вот тут пример как реализовывать итератор самостоятельно, и насколько меньше писать используя boost.stl_interfaces

Можешь выбрать любой вариант(я бы использовал boost)

(в требованиях С++14 компилятор)

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от pavlick

Рейнжи и итераторы связаны довольно мало. Концепты тут вообще ни при чем (хотя можешь их применить для упрощения тестирования, воткнув несколько static_assert с requires { some_iterator_concept } в качестве условия).

Пример итератора можешь найти здесь, не забудь учесть замечания из комментов.

Сделать член-тип таг (random_access_iterator_tag, например),

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

а весь этот iterator_traits интерфейс не нужен будет?

iterator_traits – нужен удобного извлечения информации из произвольного итератора, и, особенно, единого способа работать как с итераторами, так и с указателями. В своей реализации итератора ты никак с ним не взаимодействуешь в общем случае, хотя (начиная с С++20) и можешь специализировать тег напрямую в iterator_traits.

Ну а чего они его легаси обзывают.

std::iterator_traits – никак не легаси. Возможно, вы путаете с std::iterator, который объявлен deprecated, так как количество бойлерплейта он уменьшает только для примитивных юзкейсов, при этом чреват труднонаходимыми ошибками.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 3)
Ответ на: комментарий от anonymous

Владимир, после всего вами написанного, не вам осуждать других. Вы еще за свои «lexsem»’ы не ответили.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

iterator_traits – нужен удобного извлечения информации из произвольного итератора, и, особенно, единого способа работать как с итераторами, так и с указателями. В своей реализации итератора ты никак с ним не взаимодействуешь в общем случае, хотя (начиная с С++20) и можешь специализировать тег напрямую в iterator_traits.

Да начиная с цпп11 он как бы нах не нужен, все типы можно вывести через всякие decltype и auto, просто костыль из прошлого.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Можно, но зачем? Из указателей вам типы придется доставать иначе, так как это примитивный тип. Для единообразной обработки указателей (которые суть random-access итераторы) и итераторов вам придется писать свой iterator_traits на коленке. Вот только iterator_traits уже написан.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от Siborgium

Зачем? iterator_traits это просто соглашение об интерфейсе, все требования собраны в одном месте, их спользуют стд алгоритмы. Но после цпп11 стд алгоритмы можно написать так, что они сами будут выводить необходимые типы, не надо им больше лезть в контейнер и брать оттуда тип. А мне, как автору пользовательского контейнера, ничего писать не надо, лишь операторы необходимые ([], ++, …).

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

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

Нет, нельзя. Как только вам понадобится тег, вам придется воспользоваться iterator_traits (вернее, пришлось бы до С++20).

не надо им больше лезть в контейнер

В контейнер и так никто не лезет, типы берутся из итератора.

автору пользовательского контейнера, ничего писать не надо, лишь операторы необходимые ([], ++, …).

Серым по темно-серому пишу

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

В своей реализации итератора ты никак с ним [с iterator_traits] не взаимодействуешь

Тайпдефы и операторы, все. Тайпдефы можно из операторов и вывести.

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от Siborgium

Так сейчас концепты на каждый чих и тип итератора (output, random, …). Да и раньше можно было закостылить через SFINAE. Нафиг таги? Но вместо причесывания алгоритмов они продвигают ranges, пока мне так видится это все.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Так сейчас концепты на каждый чих […] Нафиг таги?

Как же вы меня одолели. Специально для вас процитирую свое сообщение, на которое вы отвечаете:

Как только вам понадобится тег, вам придется воспользоваться iterator_traits (вернее, пришлось бы до С++20).

Но вместо причесывания алгоритмов они продвигают ranges

И правильно делают. На чем, по вашему, работают ranges? На уровне железа угадывают, какая у вас структура данных и как по ней итерироваться, или что?

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от pavlick

Да и раньше можно было закостылить через SFINAE. Нафиг таги?

SFINAE придумали гораздо позже. Можно почитать историю, когда какие патерны придумали.

А дальше обратная совместимость…

Если бы писали сейчас, то многое было бы сделано по-другому. Тот же полиморфизм был бы как в Rust…

fsb4000 ★★★★★
()
Ответ на: комментарий от Siborgium

На чем, по вашему, работают ranges? На уровне железа угадывают, какая у вас структура данных и как по ней итерироваться, или что?

Я пока не готов на эту тему спорить, концепты еще не смотрел плотно. Но чисто теоретически - если я вижу член-функцию operator[], то логично, что перед нами random access iterator, не?

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

не?

Не. operator[] есть у двух типов итераторов:

random access iterator и continguous_iterator

fsb4000 ★★★★★
()
Ответ на: комментарий от pavlick

При чем тут концепты, господи. Еще раз цитирую себя:

Концепты тут вообще ни при чем

Концепт – грубо говоря, предикат времени компиляции. Предикат не удовлетворен – ошибка. Он абсолютно ортогонален итераторам.

чисто теоретически - если я вижу член-функцию operator[],

Как вы ее видите? «Увидеть» ее можно было через SFINAE, сложно и больно, и теперь можно через концепт.

ranges точно так же ортогональны концептам. Упрощенно, ranges – сахар над итераторами, их обобщение. Вместо пары итераторов begin-end теперь range, внутри которого та же самая пара итераторов. Это не освобождает вас от написания итераторов, это освобождает юзера от постоянного написания begin-end руками и ошибок при итерации по указанному окну.

Siborgium ★★★★★
()
Ответ на: комментарий от pavlick

вижу член-функцию operator[], то логично, что перед нами random access iterator

Вектор тоже имеет член-функцию operator[]. И даже value_type есть, и reference_type. Он теперь random access iterator?

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

При чем тут концепты, господи.

При том, что всю необходимую инфу можно получить без всяких type_traits в новых плюсах. А раз так, то зачем основывать концепты для итераторов на legacy-deprecated дерьме? Но это пока просто гипотеза, повторяю - итераторные концепты пока не копал.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

При том, что всю необходимую инфу можно получить без всяких type_traits в новых плюсах.

Вы уже какой, четвертый (?) раз повторяете эту фразу. До вас никак не дойдет, что я согласен с ней, что явно выразил еще в самом начале, и что я говорю про совсем другие вещи.

Еще один раз. Концепты никак не помогут вам писать итератор. Они помогут вам использовать итератор.

зачем основывать концепты

Зачем вам концепты для работы итератора? Ответите на вопрос – приходите.

Siborgium ★★★★★
()
Ответ на: комментарий от pavlick

При том, что всю необходимую инфу можно получить без всяких type_traits в новых плюсах. А раз так, то зачем основывать концепты для итераторов на legacy-deprecated дерьме?

они и не основывают. Для концептов не нужны таги, только необходимые операторы.

вот пруф: https://gcc.godbolt.org/z/YTKqha

(там внизу статик ассерт, а в итераторе нет тайпдефов, кроме value_type)

fsb4000 ★★★★★
()
Ответ на: комментарий от Siborgium

А где я писал, что они помогут писать итератор? Это все нужно внутри стд алгоритмов, для выбора нужных подалгоритмов для каждого типа итератора (advance, например, перегрузка по типу тага.). Ну а если концепты основываются не на легаси механизмах, то мне, как автору итератора, не надо делать все эти тайпдефы - интерфейс из прошлого.

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Спс за код. Вот, я примерно об этом и подозревал.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Ну а если концепты основываются не на легаси механизмах, то мне, как автору итератора, не надо делать все эти тайпдефы - интерфейс из прошлого.

Концепты не основываются на легаси механизмах.

Но обычные алгоритмы для итераторов основываются на LegacySomethingIterator

Вот смотри:

std::partition

https://en.cppreference.com/w/cpp/algorithm/partition

LegacyForwardIterator

а ranges алгоритмы нет:

std::ranges::partition

https://en.cppreference.com/w/cpp/algorithm/ranges/partition

ranges::forward_range и https://en.cppreference.com/w/cpp/ranges/forward_range

Никаких Legacy нет.

Так что если хочешь чтобы пользователь мог пользоваться не только range алгоритмами, то лучше определяй тайпдефы…

fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Вот, я ведь о том и толкую )). Вместо допиливания алгоритмов (перестать требовать итераторы зависеть от легаси дерьма), на них забили и вылизывают рейнджи. Видимо стд::алгоритмам уготована место на свалке истории. Сначала скромно легаси, а пототм влепят deprecated.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

павлик, ты утомил, почитай что-нибудь по теме. тебе уже раз 5 сказали, что ренжи, итераторы и алгоритмы ортогональны. ренж - это пара итераторов, вернее то у чего есть begin() и end(). алгоритм - работает с итераторами к которым предъявляются некоторые требования, в зависимости от алгоритма. ренжовые алгоритмы работают с ренжами, которые есть пара итераторов, вернее нечто у чего есть begin() и end().

скорее всего ты путаешь алгоритмы и вью/адаптеры. take(5) - это не алгоритм, это вью, это вью начнёт материализоваться по мере того как ты будешь доставать из него данные, то есть ленивым способом.

там есть какие-то алгоритмы тоже, но в основном ренжи - это не алгоритмы, а вью и адаптеры. в стандарт вообще мало что попало из ренжей. в стандартной библиотеке штук 10 вью, а в ренж-в3 их штук 100.

anonymous
()
Ответ на: комментарий от anonymous

Ну что ты пишешь, ну ты почитай сам сначала что-нибудь, загляни сюда для всех «старых» алгоритмов цпп20 добавил range алгоритмы, и это не вью, а экшены c «eager algorithm» как их называют. А вью там далеко не десять, просто не все еще задокументировали и закодили в стд.

pavlick ★★
() автор топика
Ответ на: комментарий от pavlick

Короче успокойся ты все правильно понял, это текущий вектор развития, еще одна попытка обмазаться абстракцией по второму слою. Знаешь выражение «создавать вид кипучей деятельности»? Вот это оно и есть. Пацанам надо было что-то сделать для нового стандарта, пацаны что-то сделали. Принимайте.

anonymous
()
Ответ на: комментарий от pavlick

павлик, я не знаю как тебе ещё объяснить. ну так получилось, что ренжовые алгоритмы, внезапно, работают с ренжами, кто бы мог подумать. но внутри они часто вызывают обычные стд-алгоритмы, просто берут и вызывают. это по сути одно и то же, просто разный интерфейс.

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

anonymous
()
Ответ на: комментарий от anonymous

ну зачем такое писать? некоторые алгоритмы можно реализовать эффективнее на с++20, что ренжовые алгоритмы и эксплуатируют, а классические алгоритмы из стд должны работать на с++98 и не должны ломать обратную совместимость.

но определённый вектор развития в этом конечно есть. ренжи будут жить в ranges как время живёт в chrono например, а не всё свалено в один неймспейс. это же хорошо?

anonymous
()
Ответ на: комментарий от fsb4000

Да, видел, благодарю. Я в итоге вообще другим путём пошел, не стал свой итератор делать.

ЗЫ: спасбо тому человеку, кто пропихнул в цпп if constexpr, писать шаблоны стало прям приятно.

pavlick ★★
() автор топика
Последнее исправление: pavlick (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.