Re[16]: Откуда эта лютая любовь к знаковым целым?
От: Evgeny.Panasyuk Россия  
Дата: 10.05.20 08:43
Оценка:
Здравствуйте, netch80, Вы писали:

N>>>Тут надо было бы пример подправить — reverseFor(i: n..1)

EP>>Зачем? Обычно в таких случаях нужны либо индексы, либо просто n итераций — в обоих случаях while(n--) отрабатывает на ура
N>Случай — он разный бывает. Я показываю, на каком варианте итерации "лаконичность" кода с while(n--) исчезает или превращается в недостаток.

А я как бы и не агитирую за это как за самое универсальное и обобщённое решение.
Моя позиция в том, что лучше иметь разные варианты решений в своём инструментарии, особенно если у них есть уникальные плюсы, а не слепо отвергать их из-за каких субъективных предрассудков.
За всякими хаками частенько стоит набор аксиом, концепций, теорем — и то что выглядит на первый взгляд как хак, на самом деле имеет под собой вполне строгую математику

EP>>Запоминается один раз и используются всю жизнь. Повторюсь, встречается повсеместно, рано или поздно всё равно придётся разок посмотреть на эти новые ворота.

N>Я лет 20 достаточно плотно пишу на C и читаю сишный код, и такую идиому встречал максимум пару раз, а скорее даже реже.
N>Мой мир — на 98% обычный юниксовый userland, на пару процентов — ядро (Linux, FreeBSD, OpenBSD) — и я не помню, чтобы там кто-то где-то использовал эти заклинания. Возможно, её применяют в каком-то особом подмирке, типа определённого embedded? Расскажите, где это у вас "встречается повсеместно".

Ваше благородие, соизвольте заглянуть в ядро Linux следующим grep'ом:
linux-master $ grep -r 'while\s*(\s*[[:alnum:]_]*\s*--\s*).*[^;]' | wc -l
1148

linux-master $ grep -r 'while\s*(\s*[[:alnum:]_]*\s*--\s*).*[^;]' | head -n25
arch/alpha/kernel/io.c:         while (count--) {
arch/alpha/kernel/io.c:         while (count--) {
arch/alpha/kernel/io.c:         while (count--) {
arch/alpha/kernel/io.c:         while (count--) {
arch/alpha/kernel/io.c:                 while (count--) {
arch/arc/include/asm/syscall.h: while (n--) {
arch/arm/mach-davinci/board-dm644x-evm.c:       while (ngpio--) {
arch/arm/mach-davinci/board-dm646x-evm.c:       while (ngpio--) {
arch/arm/mach-exynos/mcpm-exynos.c:     while (tries--) {
arch/arm/mach-orion5x/kurobox_pro-setup.c:      while (count--) {
arch/arm/mach-orion5x/terastation_pro2-setup.c: while (count--) {
arch/arm/mach-pxa/pxa3xx-ulpi.c:        while (timeout--) {
arch/arm/mach-rpc/ecard.c:              while (len--) {
arch/arm/mach-rpc/ecard.c:                      while (len--) {
arch/arm/mach-rpc/ecard.c:                      while(len--) {
arch/arm/mach-socfpga/ocram.c:  while (limit--) {
arch/arm64/crypto/aes-glue.c:           while (blocks--) {
arch/ia64/hp/common/sba_iommu.c:                                while (cnt--) {
arch/ia64/hp/common/sba_iommu.c:                while (cnt--) {
arch/ia64/kernel/cyclone.c:             while(stall--) barrier();
arch/ia64/kernel/mca.c: while (slots--) {
arch/ia64/kernel/setup.c:       while (max--) {
arch/m68k/amiga/config.c:       while (count--) {
arch/m68k/apollo/config.c:   while(count--) {
arch/m68k/atari/debug.c:        while (count--) {


Ну или в ядро *BSD, что там ближе

EP>>Идиома, кстати, применима и к итераторам — у которых может даже и не быть operator<

N>От замены в аналоге "i-->1" на "i--!=1" теряется только визуальная красота стрелки.

А я не об этом. Я о том что вот этот вариант: for (int i=n-1; i>=0; --i) на итераторы не переносится в общем случае, из-за отсутствия отношения порядка и one-before-last. А вариант while(it-- != first) — работает, потому что requires более общие concepts. Вот такой вот "хак".
Точнее one-before-last обходится переносом декремента на первую строчку тела (как уже показывали ранее в этой теме): while(it != first){--it; ...}, но концептуально то же самое.

N>А именно для итераторов в C++ давно придуманы rbegin и rend,


Спасибо кэп, а то ж я не знал.

N>которые, как описано, реализуют хак, который надо отрабатывать явным декрементом.


Хак в base не так паршиво, как хак при разыменовании.
Существует он как раз из-за отсутствия упомянутого мной one-before-first в общем случае. В тех же случаях где мы можем гарантировать валидность итератора one-before-last по построению, этот хак не нужен, и используется более быстрый адаптор без лишних передёргиваний.

N>То есть для обратного прохода это превратилось бы в такое:

N>
N>for (unsigned fi = n; fi >= 1; --fi) { // ну или fi != 0, без разницы
N>  unsigned i = fi - 1; // разрезолвляем обратный итератор в прямой :)
N>  bar(i);
N>}
N>


О том и речь, именно поэтому прямое итерирование вниз может быть предпочительней стандартного reverse_iterator — так как без лишних передёргиваний. Если нужно часто — реализуй в виде ФВП.
Отредактировано 10.05.2020 9:27 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 10.05.2020 9:01 Evgeny.Panasyuk . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.