Russian Qt Forum

Программирование => С/C++ => Тема начата: AkonResumed от Апрель 03, 2021, 06:47



Название: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 03, 2021, 06:47
Имеем такой шаблон функции, где нужно в зависимости от того, прямой на входе итератор или реверсивный (reverse_iterator) генерировать ту или уную константу:
Код:
template <typename IteratorT>
static void shiftWeeks(IteratorT begin, IteratorT end)
{
    ....
    static const int DayStep = 7 * (IsReverseIterator<IteratorT> ? -1 : 1);
    ....
}

Задействовать контейнер (подавать его на вход функции) нельзя.

Пока что прицепился к reverse_iterator::base() - этой функции нет у iterator:
Код:
template <typename, typename = void>
inline constexpr bool IsReverseIterator = false;

template <typename T>
inline constexpr bool IsReverseIterator<T, std::void_t<decltype(std::declval<T>().base())>> = true;

В С++17 более никаких compile-time отличий не нашел (а хотелось бы какой-нибудь тэг направления). Допускаю, что что-то пропустил. И, кто уже юзает C++20, - как там в плане новшеств этом вопросе?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: m_ax от Апрель 07, 2021, 15:09
Цитировать
В С++17 более никаких compile-time отличий не нашел (а хотелось бы какой-нибудь тэг направления). Допускаю, что что-то пропустил. И, кто уже юзает C++20, - как там в плане новшеств этом вопросе?
Не знаю, что там в 20 стандарте, но похоже, ничего другого, кроме как зацепиться за base() не остаётся..
Да, хотелось бы, чтоб в iterator_traits был teg типа: revers_ iterator_tag, но увы.. (даже не представляю, как это можно реализовать..)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 07, 2021, 15:22
[off]Недавно пришлось "собирать" больше десятка приложений чтобы посмотреть "как это там сделано". Прослеживается четкая зависимость: где больше С++ 17 и.т.п. - там меньше мыслей (вернее вообще нет, что-то придумать даже не пытался). Конечно "лучше быть богатым и здоровым", но голова-то одна. Ни к чему "через край" жрать этот сахар
[/off]


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: m_ax от Апрель 07, 2021, 15:36
Цитировать
[off]Недавно пришлось "собирать" больше десятка приложений чтобы посмотреть "как это там сделано". Прослеживается четкая зависимость: где больше С++ 17 и.т.п. - там меньше мыслей (вернее вообще нет, что-то придумать даже не пытался). Конечно "лучше быть богатым и здоровым", но голова-то одна. Ни к чему "через край" жрать этот сахар
[/off]
Ну тут я не вправе Вам что-то советовать.. Решайте сами  :)

P.S.
На мой вкус, решение приведённое выше, весьма адекватное..


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 07, 2021, 16:00
Прослеживается четкая зависимость: где больше С++ 17 и.т.п. - там меньше мыслей (вернее вообще нет, что-то придумать даже не пытался).
Вам так показалось потому, что вы не поняли что там написано. :)
Большинству разработчиков не повезло так как вам, им не достаточно для выражения всех своих мыслей, использовать только QVector и циклы с индексами. :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: m_ax от Апрель 07, 2021, 16:20
Я согласен.. Тут просто других вариантов просто тупо нет..


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: m_ax от Апрель 08, 2021, 00:13
AkonResumed Вы не обращайте внимания.. У нас тут подобного рода дебаты  - это нормально  :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 14, 2021, 17:11
Большинству разработчиков не повезло так как вам, им не достаточно для выражения всех своих мыслей, использовать только QVector и циклы с индексами. :)

На самом деле проблема то более глубокая.
QVector и циклы с индексами поймёт, пожалуй, 10 из 10 разрабов (даже которые C++ не видели).
std::void_t<decltype(std::declval<T>().base())>> и иже с ними - ну, скажем, 5 из 10, что видели C++ (по личному наблюдению).
Пофиксить возникшие баги смогут 2-3 из них.
Какой вариант выберет бизнес, которому надо "всё и быстро"?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 14, 2021, 21:31
Racheengel, вы абсолютно правы. Бизнес выберет что-нибудь типа Java. И это будет лучшим для него выбором. Более того, если утвержден некий "потолок сложности" в проекте, то все попытки выхода за него должны неумолимо пресекаться.

Просто, как и много где, есть сегментация. С++ с современными шаблонами - это ближе к high-end.



Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 10:09
Racheengel, вы абсолютно правы. Бизнес выберет что-нибудь типа Java. И это будет лучшим для него выбором. Более того, если утвержден некий "потолок сложности" в проекте, то все попытки выхода за него должны неумолимо пресекаться.

Просто, как и много где, есть сегментация. С++ с современными шаблонами - это ближе к high-end.

Да, Java как мейнстрим, или шарп.
Но для high-performance систем бизнес скорее всё-таки выберет Embedded/C/C++.
И "потолок сложности", а скорее критерий приемлемости, по сути определяется несколькими факторами, главные из которых - производительность, стабильность и поддерживаемость кода.
Дают ли "современные шаблоны" преимущество в этих аспектах? Наверное, скорее нет.
Во всяком случае код "на шаблонах" вряд ли будет быстрее кода "на векторах и циклах".
А если посмотреть на медицинскую отрасль - то там даже наследование не всегда разрешается использовать.

(отредактирую пожалуй, а то начались разночтения: high-end != high-performance)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 10:12
std::void_t<decltype(std::declval<T>().base())>> и иже с ними - ну, скажем, 5 из 10, что видели C++ (по личному наблюдению).
Пофиксить возникшие баги смогут 2-3 из них.
То да. Конечно разобраться с таким вумным кодом можно. Более того, это даже интересно. Напр я ничего не слышал о declval, прочел эту тему, открыл справочник - оказывается и так можно! Но это совершенно непроизводительная, непродуктивная и.т.п. растрата времени и интеллектуальных ресурсов.

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

В общем, все хорошо в меру  :)

Просто, как и много где, есть сегментация. С++ с современными шаблонами - это ближе к high-end.
Что такое high-end ?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 10:35
Хм, кстати по поводу high-end: кэмбриждский словарь определеят эту фразу как "used to describe a business that makes or sells expensive products".
То есть в случае софта, поддержка подобных продуктов обойдётся очень дорого, что в принципе правда.


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 10:52
Но это совершенно непроизводительная, непродуктивная и.т.п. растрата времени и интеллектуальных ресурсов.

И дополню: больше всего страдает сам вумник. Ведь время и силы, затраченное на "достижение совершенства"  берутся из проекта/задачи, связь с которой знаток быстро теряет. А приобретенные обширные познания этого отнюдь не компенсируют.
Какая чушь. :)
То что вы не можете разобраться с элементарными вещами типа итераторов и на это у вас уходит огромное количество времени и "интеллектуальных" ресурсов, не говорит о том, что у всех такие же проблемы.
Большинство людей изучающих C++ разбираются с итераторами (что это такое, для чего нужны и как их использовать) еще на этапе изучения, а дальше просто используют их в своей работе. Им не нужно всякий раз, когда они видят итераторы в чужом коде, лезть в справочники или на хабр, что бы понять что хотел выразить автор кода. :)
Так же происходит и с другими возможностями C++. Перегрузки интеллектуальных ресурсов это не вызывает... ну у большинства разработчиков... :)
Сколько вы потратили времени и  "интеллектуальных" ресурсов на разбирательство с declval? :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 15, 2021, 12:08
Под "high-end" я подразумевал мастерство разработчика, из которого автоматом вытекают гибкость и производительность (скорость выполнения кода). Если не вытекают - это антимастерство.

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


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 12:38
Под "high-end" я подразумевал мастерство разработчика, из которого автоматом вытекают гибкость и производительность (скорость выполнения кода). Если не вытекают - это антимастерство.

Да, конечно.
Но кроме этого, есть ещё аспекты сопровождаемости кода (как людьми - онбоардинг и расширяемость, так и техническими средствами - например, время компиляции).
И, честно говоря, "современные шаблоны" как-то не совсем входят в этот high-end, а скорее в вот тот другой, который дорого поддерживать.
ИМХО один из лучших принципов разработки, которого придерживаются мастера - это пресловутый KISS.
Как правило, именно он даёт в итоге максимум гибкости, производительности и стабильности.



Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 12:43
ИМХО один из лучших принципов разработки, которого придерживаются мастера - это пресловутый KISS.
Вы считаете, что мастера не используют итераторы? :)
Итераторы - что может быть KISS-овей в C++? :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 12:48
Вы считаете, что мастера не используют итераторы? :)
Итераторы - что может быть KISS-овей в C++? :)

О не, наоборот, итераторы это хорошо :) Куда ж без них родимых...



Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 12:48
Под "high-end" я подразумевал мастерство разработчика, из которого автоматом вытекают гибкость и производительность (скорость выполнения кода). Если не вытекают - это антимастерство.
Ну вот хотя бы данная тема. Не вижу каким боком это вообще связано с производительностью. С гибкостью тоже не блеск, разве нельзя было без затей подать +/- 1 как аргумент, пусть в неск ф-ций? Народная примета: когда видишь "большую вумность" ищи "чему она посвящена"  :) А возможность declval интересная, не спорю, но "не более того"

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


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 12:54
О не, наоборот, итераторы это хорошо :) Куда ж без них родимых...
Как куда? Взял QVector + индексы... Индексов хватит всем... :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 13:02
Как куда? Взял QVector + индексы... Индексов хватит всем... :)

Ну, индексы и итераторы - вещи не (всегда) взаимозаменяемые... Хотя я больше люблю типа: for (auto& x: y)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 13:14
ИМХО один из лучших принципов разработки, которого придерживаются мастера - это пресловутый KISS.

а потом я вычищаю из кода такое

Код:
if (!hash.contains(key)) {
    hash.insert(key, 0);
}
hash[key]++;


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 13:15
Хотя я больше люблю типа: for (auto& x: y)

Зачем вы себя так гробите? :)

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

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


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 13:52
а потом я вычищаю из кода такое

Код:
if (!hash.contains(key)) {
    hash.insert(key, 0);
}
hash[key]++;
Не надо перегибать палку. Но если уж разговор о хеше, то замечу что совсем недавно обсуждали здесь с научным работником создание хеша "на лету". Не услышал ни одной мысли, хотя наши познания в "современном С++" несравнимы. Обильные знания не всегда помогают найти хорошее решение, а иногда и вредят.

 


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 13:55
Обильные знания не всегда помогают найти хорошее решение, а иногда и вредят.
Знания они вообще вредные. :)
Есть хорошая поговорка на этот счет: Меньше знаешь, крепче спишь. :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 14:05

а потом я вычищаю из кода такое

Код:
if (!hash.contains(key)) {
    hash.insert(key, 0);
}
hash[key]++;


Ну, джун писал, чо... Неэффективно! Надо таКЪ:

Код:
if (hash.contains(key))
    hash[key]++;
else
    hash.insert(key, 1);

:)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 14:14
Ну, джун писал, чо... Неэффективно! Надо таКЪ:

Код:
if (hash.contains(key))
    hash[key]++;
else
    hash.insert(key, 1);

:)
Один поиск все равно лишний... :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 14:37
Не надо перегибать палку.

Я не перегибаю, практика показывает, что люди, не знающие итераторов также не знают что operator[] возвращает ссылку (которую можно менять) или что такое explicit.


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 14:40

Один поиск все равно лишний... :)

ну вообще это просто

Код:
hash[key]++;

но это уже надо знать про то что operator[] создает default-constructed T - это же не циклы с индексами писать, это справочники читать надо


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 14:42
ну вообще это просто
Ну вообще, я это знаю, поэтому и написал про это Racheengel и предоставил возможность подумать. :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 15, 2021, 14:49
Друзья, все по-своему правы (зависит от контекста). Пожалуй, чтобы лучше "прочувствовать" приведу здесь саму задачу, решая которую и создал этот топик. Это типовая задача, в которой есть связь типа и константы. 

Итак, задача: есть диапазон дат (QDate), задаваемый парой итераторов [begin, end). Даты идут с шагом в 7-дней. Необходимо сдвинуть диапазон влево или вправо на любое заданное число элементов, при этом новые даты должны продолжать последовательность.

Например, [2021-04-8,   2021-04-15,   2021-04-22] после сдвига влево на 2 станет [2021-04-22,   2021-04-29,   2021-05-06], а после сдвига на 4 - [2021-05-06,   2021-05-13,   2021-05-20].

Это отдаленно похоже на std::shift_left, std::shift_right из C++20, но мы ограничены C++17.

Допустимо сделать две функции shift_left и shift_right, а можно обойтись и одной shift, в которой направление сдвига задается типом итераторов (прямой - влево, обратный - вправо) или знаком смещения ('+' - влево, '-' - вправо). Это на ваш выбор.

Например, если направление сдвига задаем типом итератора (соот-но, будет беззнаковое смещение), то прототип такой:
Код:
template <typename IteratorT>
void shift(IteratorT begin, IteratorT end, typename std::iterator_traits<IteratorT>::difference_type offset)

Если мысленно представите или набросаете решение, при этом стремясь к элегантности, которая в данном случае даст гибкость, производительность, включение универсальности ... и будет мало букв в коде, то поймете мой изначальный вопрос.   


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 15:14

Один поиск все равно лишний... :)

ну вообще это просто

Код:
hash[key]++;

но это уже надо знать про то что operator[] создает default-constructed T - это же не циклы с индексами писать, это справочники читать надо

Эт верно, но только если гарантируется, что для default-constructed T будет 0 :)
А если нет - хм, возможен ведь и такой варинт...
Или же мы хотим не 0 по дефолту, а там 100 например?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 15:22
Я не перегибаю, практика показывает, что люди, не знающие итераторов также не знают что operator[] возвращает ссылку (которую можно менять) или что такое explicit.
Я не сделаю такой ошибки, но не считаю что знаю итераторы. Как-то хотел написать итератор с нуля "по всем правилам", открыл справочник - ой мама, та ну его нафиг  :)

Плохо не то что человек "много знает" (да на здоровье), а то что он (чрезмерно) увлечен поглощением знаний, и найти свое решение даже не пытается. Ну вот та задачка на хеш что я упоминал
Цитировать
- Есть контейнер нормированных QVector3D. Требуется макс быстро находить в нем все вектора с углом отклонения не больше заданного от вектора V (аргумент поиска). При этом кратность невелика, число поисков напр всего 200 (потом контейнер изменится)
Я хорошо знаю как это будет делать std-шник. Если думка об ускорении вообще возникнет в его голове, то будет сразу же отметена - ведь построение std::unordered_map явно дороже 200 переборов. И он с чистой совестью влепит перебор вроде std::find, вероятно с лямбдой и.т.п. В его понимании это нормально, т.к. find - штатная ф-ция. Хуже всего что у него нет и желания что-то придумать, ведь неуклонно овладевать все новыми и новыми знаниями куда легче, безопаснее и приятнее. А как же "high-end"? Да хз  :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 15:23
Эт верно, но только если гарантируется, что для default-constructed T будет 0 :)
А если нет - хм, возможен ведь и такой варинт...
Или же мы хотим не 0 по дефолту, а там 100 например?


придется почитать букварь и выяснить что operator[] таки возвращает ссылку
Код:
int &value = hash[key];
if (value == 0)
    value = 100;
else
    value++;


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 15, 2021, 15:31
Я хорошо знаю как это будет делать std-шник.
...
Хуже всего что у него нет и желания что-то придумать, ведь неуклонно овладевать все новыми и новыми знаниями куда легче, безопаснее и приятнее.
Серьезно? Знаете? Как любой std-шник будет делать? :)
А скольких std-шников вы знаете? Вы правда уверены, что это все std-шники в программировании? :)

P.S. Чем меньше человек знает, тем масштабнее у него заявления... :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 15:37
придется почитать букварь и выяснить что operator[] таки возвращает ссылку
Код:
int &value = hash[key];
if (value == 0)
    value = 100;
else
    value++;

Почти хорошо, т.к. *But for primitive types like int and double, as well as for pointer types, the C++ language doesn't specify any initialization; in those cases, Qt's containers automatically initialize the value to 0.

Но только если в хэше уже раньше был 0-й ключ, то он превратится в 100, а не в 1... Понимаю, что пошла уже софистика, но возможно "джун" был не совсем туп :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 15:39
Итак, задача: есть диапазон дат (QDate), задаваемый парой итераторов [begin, end). Даты идут с шагом в 7-дней. Необходимо сдвинуть диапазон влево или вправо на любое заданное число элементов, при этом новые даты должны продолжать последовательность.

Например, [2021-04-8,   2021-04-15,   2021-04-22] после сдвига влево на 2 станет [2021-04-22,   2021-04-29,   2021-05-06], а после сдвига на 4 - [2021-05-06,   2021-05-13,   2021-05-20].
Ну а почему бы не перевести в нечто вроде "день эпохи", там спокойно отнять или прибавить недели, и потом обратно в даты?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 15:53
Почти хорошо, т.к. *But for primitive types like int and double, as well as for pointer types, the C++ language doesn't specify any initialization; in those cases, Qt's containers automatically initialize the value to 0.

Кутешные контейнеры тут ни при чем - если элемента нет, вставляется default-constructed value, что для int'а 0 по стандарту. default-constructed value != uninitialized variable. Но это же букварь читать надо, тонкости языка знать, это не циклы с индексами писать=)

Но только если в хэше уже раньше был 0-й ключ, то он превратится в 100, а не в 1... Понимаю, что пошла уже софистика, но возможно "джун" был не совсем туп :)

Ну это действительно софистика, потому что исходный код считал с нуля но зачем-то делал 3 лукапа.


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 15:53
Итак, задача: есть диапазон дат (QDate), задаваемый парой итераторов [begin, end). Даты идут с шагом в 7-дней. Необходимо сдвинуть диапазон влево или вправо на любое заданное число элементов, при этом новые даты должны продолжать последовательность.

я так понимаю, сдвиг на N - это "прибавить N недель к каждой дате"?

тогда (псевдокод):

Код:
void shift(IteratorT begin, IteratorT end, int offset)
{
  for (auto& it = begin; it != end; it++)
  {
    *it = (*it).addDays(offset * 7);
  }
}

это имелось в виду? :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 15:57
Кутешные контейнеры тут ни при чем - если элемента нет, вставляется default-constructed value, что для int'а 0 по стандарту. default-constructed value != uninitialized variable. Но это же букварь читать надо, тонкости языка знать, это не циклы с индексами писать=)

Дык это я как раз строчку с "букваря" (документации по QHash) взял. Там написано, что "по стандарту" int не обязан нулём инициализироваться, поэтому для хэша они это "сами заимплементировали".


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 16:11
Дык это я как раз строчку с "букваря" (документации по QHash) взял. Там написано, что "по стандарту" int не обязан нулём инициализироваться, поэтому для хэша они это "сами заимплементировали".
Плиз "ткните носиком" где прочитали, не припомню ни одного контейнера который бы имел неинициализированные эл-ты. Ну разве QVarLengthArray, но там умышленно.


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 16:14

Дык это я как раз строчку с "букваря" (документации по QHash) взял. Там написано, что "по стандарту" int не обязан нулём инициализироваться, поэтому для хэша они это "сами заимплементировали".

Ну кутешные контейнеры пишут такие же специалисты как те которые в итераторах не могут разобраться=)
В Qt6 например QHash не обеспечивает стабильность ссылок при вставке что ломает тонну кода.
Вы читайте cppreference - там требование к T чтобы он был default-constructible для operator[]. Интересно, зачем надо default-constructible кроме как чтобы позвать T() (подсказка - int a; дефолт ктор не зовет)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 16:14
Плиз "ткните носиком" где прочитали, не припомню ни одного контейнера который бы имел неинициализированные эл-ты. Ну разве QVarLengthArray, но там умышленно.

Вздох.
std::vector::reserve ?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 15, 2021, 16:27
Вздох.
std::vector::reserve ?
А это вовсе не эл-ты, а место для них (т.е. личное дело контейнера).

Ну кутешные контейнеры пишут такие же специалисты как те которые в итераторах не могут разобраться=)
В Qt6 например QHash не обеспечивает стабильность ссылок при вставке что ломает тонну кода.
??? Так всегда было, неперемещаемость только для erase, для вставок и remove "пионерский привет" (rehash)

Вы читайте cppreference - там требование к T чтобы он был default-constructible для
Не стоит так "хвост распускать"  :), дойдет до дела (выше) - будет обычная история  :'(


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 15, 2021, 16:46
??? Так всегда было, неперемещаемость только для erase, для вставок и remove "пионерский привет" (rehash)

хэш (обычно) это массив линкед-листов. при реаллокации массива, внезапно, адреса (и ссылки на элементы) нодов линкед листов не меняются - эту гарантию даёт, например, std::unordered_map.
можно действительно хэш реализовать другими способами, и тогда при раллокации адреса могут поехать, но в qt5 он был старым-добрым массивом линкед-листов и давал гарантию при insert'e (по крайней мере, оно работало на практике)
Но как минимум странно имея имплементацию "по стандарту" менять ее на другую которую захотела левая пятка, поломав кучу кода.
При переходе на qt6 код ломается, и самое простое решение - выкинуть QHash нафиг и использовать std::unordered_map.

Не стоит так "хвост распускать"  :), дойдет до дела (выше) - будет обычная история  :'(

Просто ваши задачи требуют неадекватного количества времени чтобы понять вообще в чем задача - требования меняются каждую страницу потому что вы их "забыли" указать, но предложенное решение им (конечно же!) не удовлетворяет.
Цитировать
-я хочу сделать кнопку чтобы приложение закрывлось
-вот кнопка
-мне круглую надо
-окей
-и красную
-окей
-и чтобы шрифт зеленый
-ооок
-и чтобы диалог появлялся
-вот диалог
-да ты просто тупой, вот я взял и написал сразу круглую красную кнопку с зеленым текстом и диалогом а вы все форумом хрень какую-то предлагали. зато в шаблоны умеете!


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 17:31
Но как минимум странно имея имплементацию "по стандарту" менять ее на другую которую захотела левая пятка, поломав кучу кода.

Ну, "эффективный менеджер" видать постарался.

При переходе на qt6 код ломается, и самое простое решение - выкинуть QHash нафиг и использовать std::unordered_map.

Мы тоже давно уже всё кутэшное контейнерьё повыкидывали... Они ещё и медленные часто.


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 15, 2021, 18:36
Итак, задача: есть диапазон дат (QDate), задаваемый парой итераторов [begin, end). Даты идут с шагом в 7-дней. Необходимо сдвинуть диапазон влево или вправо на любое заданное число элементов, при этом новые даты должны продолжать последовательность.

я так понимаю, сдвиг на N - это "прибавить N недель к каждой дате"?

тогда (псевдокод):

Код:
void shift(IteratorT begin, IteratorT end, int offset)
{
  for (auto& it = begin; it != end; it++)
  {
    *it = (*it).addDays(offset * 7);
  }
}

это имелось в виду? :)
:o Блин, ну здорово!! На самом деле я неудачно упростил задачу, и вместо QDate там шаред-поинтер на класс с членом, возвращающим QDate. И нужно именно "двигать", т.е. для выдвигаемых элементов должен вызываться деструктор, а вдвигаемые должны создаваться конструктором с новой датой.

Мое упущение. И мне не пришло в голову, что вот так вот можно шунтировать!

Непосредственно на то, что я сформулировал вы привели исчерпывающее решение, ну может быть
Код:
void shift(IteratorT begin, IteratorT end, int offset)
{
  while (begin != end)
  {
    *begin++ = (*begin).addDays(offset * 7);
  }
}


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 15, 2021, 18:53
Согласен, через while покошернее смотрится :)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 16, 2021, 09:41
адреса могут поехать, но в qt5 он был старым-добрым массивом линкед-листов и давал гарантию при insert'e (по крайней мере, оно работало на практике)
Но как минимум странно имея имплементацию "по стандарту" менять ее на другую которую захотела левая пятка, поломав кучу кода.
Бегло глянул исходники на вебе, не вижу что/как там "поломано", ноды создаются с помощью allocateNode, их адреса остаются неизменными. Итераторы - да, уплыть могут, но это было всегда (см erase)

Просто ваши задачи требуют неадекватного количества времени чтобы понять вообще в чем задача - требования меняются каждую страницу потому что вы их "забыли" указать, но предложенное решение им (конечно же!) не удовлетворяет.
:) Ну вот задача на тот же хеш вверху. Я не предлагаю ее решить, она достаточно сложна. До "собсно программирования" там еще довольно далеко. Да, на таких данных/кратности что-то ускорить может только хеш, но что должно быть ключом? Конечно, такие задачи возникают не каждый день (типовых больше, и намного), но они есть, и решать их придется.

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


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 16, 2021, 09:52
Ага, оказывается "добавить дни" ф-ция есть, а я думал проблема в этом.
и вместо QDate там шаред-поинтер на класс с членом, возвращающим QDate. И нужно именно "двигать", т.е. для выдвигаемых элементов должен вызываться деструктор, а вдвигаемые должны создаваться конструктором с новой датой.
Ну извлечь диапазон, впарить новые даты, потом найти место вставки (lower_bound), и вставить. Все банально (или я чего-то не знаю)


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Old от Апрель 16, 2021, 09:59
И вот как только случается нечто "нетривиальное" (что угодно) - у знатоков возникают большие проблемы :)
Конечно, а неучи сразу решают. :)

Только решений что-то не видно, ну не считая финдреплейсов и переходничков. :)

А как только появляется хоть какая то задача, сложнее финдреплейса, неучи спешать Выдрать код из игрового движка (http://www.prog.org.ru/topic_32540_0.html)
или утащить посмотреть как сделано у других:
[off]Недавно пришлось "собирать" больше десятка приложений чтобы посмотреть "как это там сделано". Прослеживается четкая зависимость: где больше С++ 17 и.т.п. - там меньше мыслей (вернее вообще нет, что-то придумать даже не пытался). Конечно "лучше быть богатым и здоровым", но голова-то одна. Ни к чему "через край" жрать этот сахар
[/off]


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Авварон от Апрель 16, 2021, 10:44
Бегло глянул исходники на вебе, не вижу что/как там "поломано", ноды создаются с помощью allocateNode, их адреса остаются неизменными. Итераторы - да, уплыть могут, но это было всегда (см erase)


хз куда вы смотрели

https://doc.qt.io/qt-6/qtcore-changes-qt6.html#stability-of-references


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 16, 2021, 11:04
Ага, оказывается "добавить дни" ф-ция есть, а я думал проблема в этом.
и вместо QDate там шаред-поинтер на класс с членом, возвращающим QDate. И нужно именно "двигать", т.е. для выдвигаемых элементов должен вызываться деструктор, а вдвигаемые должны создаваться конструктором с новой датой.
Ну извлечь диапазон, впарить новые даты, потом найти место вставки (lower_bound), и вставить. Все банально (или я чего-то не знаю)

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

[1 2 3] -> shift_left -> 1 (dtor) [2(untoched) 3(untoched) 4(ctor)].

Короче, элемент можно удалить, добавить, сдвинуть, но не модифицировать (нет интерфеса для модификации даты).



Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 16, 2021, 12:41
Выдвигаемый элемент уничтожается (деструктор). Вдвигаемый создается конструктором с новой датой. Если же элемент остается в диапазоне (т.е. он просто сдвигается, но не выдвигается), то он остается нетронутым.

[1 2 3] -> shift_left -> 1 (dtor) [2(untoched) 3(untoched) 4(ctor)].

Короче, элемент можно удалить, добавить, сдвинуть, но не модифицировать (нет интерфеса для модификации даты).
Ну и почему это не сделать обычным удалением/вставкой? Не понимаю где проблема


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Racheengel от Апрель 16, 2021, 12:47
Вопрос: а какой критерий должен быть у вставляемых элементов? Т.е. откуда должны браться значения для них?


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 16, 2021, 13:35
Можно сделать как угодно в рамках заданного прототипа (указывал выше).

Элемент такой (все лишнее выкинул). Он создается с даты. Дату первого вставляемого элемента мы определяем из даты первого/последнего элемента диапазона (в зависимости от направления сдвига) + или - (в зависимости от направления сдвига) смещение * 7. 
Элемент:
Код:
class Week
{
public:
explicit Week(QDate date) : date_(date) {}
QDate date() const { return date_; }

private:
QDate date_;
};

Диапазон может быть задан, например, так (шаред-поинтер выкинул для упрощения):
Код:
QList<Week*> weeks = {
new Week(QDate::currentDate().addDays(-7)),
new Week(QDate::currentDate()),
new Week(QDate::currentDate().addDays(7))
};


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: Igors от Апрель 17, 2021, 09:58
Ну и почему это не сделать обычным удалением/вставкой? Не понимаю где проблема
Если установлено требование "keep ascending order" то вставка диапазона - некорректная операция, т.к. несдвинутые эл-ты могут оказаться между сдвинутыми. По той же причине некорректны все игры с шифтами. Можно конечно вставлять "по одному", но это затратно (уж точно не high-end). Предлагаю так
Код
C++ (Qt)
void OffsetRange( QList<Week *> & lst, Iter beg, Iter end, int offset )
{
// calc sort range
  auto sortBeg = beg;
  auto sortEnd = end;
 
  if (offset > 0) {
   if (end != lst.end())
    sortEnd = std::lower_bound(beg, lst.end(), (*end)->data().addDays(offset), CompDate1);
  }
  else {
   if (beg != lst.end())
    sortBeg = std::lower_bound(lst.begin(), beg, (*beg)->data().addDays(offset), CompDate1);
 }
 
// modify elements
 while (beg != end) {
   auto & dst= *beg;
   auto newP = new Week(dst->data().addDays(offset));
   delete dst;
   dst = newP;
   ++beg;
 }
 
// sort it
 std::sort(sortBeg, sortEnd, CompDate2);
}


Название: Re: Compile-time определение реверсивности итератора (reverse_iterator)
Отправлено: AkonResumed от Апрель 19, 2021, 15:34
Это несколько не то. Привожу свое решение. Это ready-to-use консольная прога. Собственно, то что нужно сделать находится в тэгах //<<<<<<<< ... //>>>>>>>>. Осмелюсь заявить, что это очень элегантное/эффективное решение ввиду того, что код инвариантен направлению сдвига. Единственный участок, использующий направление, это IsReverseIterator<IteratorT>, и притом это compule-time.

Если кто приведет еще лучше - буду очень признателен.

main.cpp
Код:
#include <QtCore/QCoreApplication>
#include <QtCore/QDate>
#include <QtCore/QDebug>
#include <QtCore/QList>
#include <QtCore/QSharedPointer>

class Week
{
public:
explicit Week(QDate date) : date_(date) { qDebug() << "Week: ctor()"; }
~Week() { qDebug() << "Week: dtor()"; }

QDate date() const { return date_; }

private:
QDate date_;
};

//<<<<<<<<

template <typename, typename = void>
inline constexpr bool IsReverseIterator = false;

template <typename T>
inline constexpr bool IsReverseIterator<T, std::void_t<decltype(std::declval<T>().base())>> = true;

/// Shifts the range of Week*s to left or right on \a offset positions (weeks). The shift direction
/// is determined by the iterators kind - forward ones indicate shifting to left (with insertion on
/// the right side future weeks) and reverse ones - to right (with insertion on the left side past
///  weeks). \a offset may be any value (even greater then the range size). Shifted out Weeks
/// are destroyed, shifted in ones are created with the proper dates.
template <typename IteratorT>
static void shift(IteratorT begin, IteratorT end,
typename std::iterator_traits<IteratorT>::difference_type offset)
{
if (Q_UNLIKELY(!offset)) return;

// std::copy() uses '!=', not '<' for iterator comparison, so values above end are invalid; we
// decompose offset as offset + offsetExceeding, where the offset < end.
auto size = std::distance(begin, end);
auto offsetExceeding = offset <= size ? 0 : offset - size;
offset -= offsetExceeding;

// Date step and first shifting into element's date
static const int DayStep = 7 * (IsReverseIterator<IteratorT> ? -1 : 1);
QDate date = (*std::prev(end))->date().addDays(DayStep * (offsetExceeding + 1));

// Shift left/right, shifted out elements are freed
qDeleteAll(begin, begin + offset);
auto pos = std::copy(begin + offset, end, begin);

// Create new elements placing them from left/right side
for (; pos != end; date = date.addDays(DayStep))
*pos++ = new Week(date);
}

//>>>>>>>>

// Just syntactic sugar for whole container. Shift direction is determined by offset's sign.
template <typename ContainerT>
static void shift(ContainerT& container, int offset)
{
if (offset > 0)
shift(container.begin(), container.end(), offset);
else if (offset < 0)
shift(container.rbegin(), container.rend(), -offset);
}

static void print(const QList<Week*>& weeks)
{
for (auto week : weeks)
qDebug() << week->date();
}

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QList<Week*> weeks = {
new Week(QDate::currentDate().addDays(-7)),
new Week(QDate::currentDate()),
new Week(QDate::currentDate().addDays(7))
};
qDebug() << "\nOriginal:";
print(weeks);

qDebug() << "\nShift left on 1:";
shift(weeks, 1);
print(weeks);

qDebug() << "\nShift right on 1, so we get the original range:";
shift(weeks, -1);
print(weeks);

qDebug() << "\nShift left on 4:";
shift(weeks, 4);
print(weeks);

qDebug() << "\nShift right on 4, so we get the original range:";
shift(weeks, -4);
print(weeks);

return a.exec();
}

ContainerShifting.pro
Код:
QT -= gui

CONFIG += c++17 console
CONFIG -= app_bundle

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target