В том и прикол, что гцц значение концепта (булевой константы) кеширует в лучшем виде.
В вот значение атомарного ограничения (но только для данного концепта) он иногда пересчитывает, а иногда кеширует. Переход с false на true он диагностирует, а в обратную сторону - не догадался. Надо будет им зарепортить, уж больно смешной недочёт. Они не предполагали, что ограничение может откатываться.
Есть разные способы откатить ограничение вида `requires{ f(x); }`.
явно запретить наилучшую сигнатуру, `= delete`
добавить конкурирующие сигнатуры, чтобы нельзя было выбрать наилучшую
какой-то ещё способ я случайно нашёл, когда писал статью, но сейчас что-то не могу вспомнить
Во-первых, у конструктора (конструкторов) может быть более одной перегрузки. Поэтому Reflect<T> по-хорошему должен был бы отдавать не один кортеж типов, а набор кортежей.
Во-вторых, если конструктор содержит шаблонные аргументы, то Caster сработает криво. Либо конструктор примет его как родного, либо не примет вообще, потому что это будет считаться двойным неявным приведением.
В-третьих, если конструктор принимает initializer_list, - то получится странное
struct X { X(std::initializer_list<int>); };
struct Y { Y(char, std::initializer_list<int>); };
// caster
struct C { template<class T> opertor T() const; };
requires{ X{}; } // якобы 0-арный
requires{ X{{C{}}}; } // int - чтобы узнать тип элемента списка
requires{ Y{C{}, C{}}; } // char, initializer_list<int> - тут всё просто
В-четвёртых, явно объявленные стандартные конструкторы - копирования/перемещения - добавят угару. Даже если они =default.
В общем, техника имеет ряд ограничений, либо её надо допиливать и тестировать на всём безумном сочетании условий.
Чиселки я привёл лишь затем, чтобы явно показать разные воплощения шаблона.
На самом деле, противоядие от "the satisfaction result is different for identical atomic constraints" состоит в том, чтобы сделать ограничения не идентичными. Для этого и надо пропихнуть переменный параметр шаблона внутрь.
// всё ещё ill-formed-опасная версия
template<class T, int I> concept boo =
requires(T x) { f(x); } // одно атомарное ограничение
&& (I != 0); // другое атомарное ограничение (ну например)
// well-formed
template<class T, int I> concept boo =
requires(T x) { f(x); I; }; // одно большое атомарное ограничение
Трюк с неявным уникальным параметром шаблона - а каждая лямбда уникальна - это дополнительный уровень. В первую очередь, чтобы не писать чиселки. Чтобы каждое воплощение шаблона было новым. Но в любом случае, придётся упоминать его внутри requires.
Но мне кажется, что это плохая практика для больших программ. Как минимум, это приведёт к размножению воплощений. Сведём с ума сперва компилятор, а затем линкер...
В куске гипса квадратное делается элементарно. Опалубка из досок, по-вашему, какая проще? А мелкие отверстия - ну, возьмите брусок и ткните в гипс до того, как он схватится.
А если программист, который сравнивает вещественные числа, как раз хорошо понимает, и следит за наличием-отсутствием погрешностей в своём коде? У него будет результат ХЗ? Или это у вас будет мнение ХЗ о его результате?
Давайте начнём с самого простого: 0.5 == 1.0 / 2.0, тут хз или не хз?
Тем не менее, банковское округление и округление от нуля - это тоже традиционные. В том смысле, что используются на практике, а не добавлено "с потолка", лишь бы было.
Поскольку "к ближайшему целому" неоднозначно для полуцелых чисел, то опытный кодер обязательно уточнил бы у собеседующего, чего именно тот хочет. А заодно и рассказал бы и про три самых популярных.
Тут, конечно, для собеседующего может прозвенеть красный звоночек overqualified, "чего это я собеседую на позицию джуна, а ко мне пришёл то ли мидл (а то и сеньор), то ли лютый зануда..."
Всё-таки, навевает огромной печалью от того, что авторы эзолангов упарываются на тему вычурного синтаксиса, но очень неглубоко. Тупейшими макроподстановками можно вычистить весь код, превратив его в какой-нибудь базовый брейнфак, форт или бейсик.
1) Административное решение. Не принимать библиотеку в ветку qa-checked или как оно там называется в вашем репозитории. А если прямо совсем мешает разработке, то отревертить в вашей основной ветке - мастер/транк/как оно там называется.
Пусть техлид отведёт фичную ветку, где займётся миграцией на новую версию библиотеки в спокойном режиме.
Как вообще можно было вмержить в мастер эпохальное изменение, минуя тесты? Или часть библиотек живёт вне репозитория? Ну хотя бы докерфайл же должен жить в репе? Значит, надо переделывать, чтобы системные зависимости тоже там оказались.
2) Выкиньте свой boid, вы рискуете отхватить проблемы в самых неожиданных местах, где будет делаться проверка на void / не-void. Потому что вжух, и там окажется не-void.
Кстати, зачем у boid конструктор от более чем одного аргумента, да ещё и с приплясыванием "кроме наследников boid"? Чую, у вас там где-то говнокод с оператором запятая притаился, который оказался вовсе не оператором...
А не хотите ли проверить, что где-то запятая ведёт себя не так, как вы ожидаете?
3) Специализация / if-constexpr в общем случае, плюс разные техники scope guard там, где они применимы.
4) Фактически, вам очень жирно подсветили, что именно ваша обвязка не умеет работать с void. Заодно проверьте, умеет ли она корректно работать с другими разнообразными типами. Ссылочные, некопируемые, неполные, - вот это всё.
Вот прямо сходу бросается в глаза:
template <typename F, typename... Args>
auto test_running_time(pcstr test_name, F&& f, Args&&... args) {
.....
auto result = gtl::invoke(gtl::forward<F>(f), gtl::forward<Args>(args)...);
.....
return result;
}
Локальная переменная по значению, и возврат по значению. Знаете, сколько граблей тут рассыпано? Часть из них можно было бы убрать с помощью decltype(auto) .
5) Юниттесты на вашу библиотеку тестов есть? Они покрывают это разнообразие?
Настоящий квиксорт на массиве - тоже неустойчивый.
Минус пирамидальной сортировки - в том, что она в лучшем случае вдвое медленнее быстрой (элементы сравниваются и перемещаются дважды - при сборке и разборке кучи).
А вот плюс - в том, что она гарантирует логлинейное время.
Промышленные методы сортировки - это сплав быстрой, вставок и пирамиды.
если массив маленький, то вставками он сортируется быстрее, просто потому, что два цикла быстрее, чем рекурсии
если глубина рекурсии превысила порог, кратный логарифму длины массива, это признак того, что набор плохой для квиксорта, и надо валить оттуда, пока мы до квадрата не доигрались, - запускают пирамиду
История реддита показывает, что как только аудитория оказывается достаточно лакомым куском для Очень Больших Политиков, они захватывают инициативу и устраивают там филиал демпартии США.
Наверное, смысл в tiny - в меньшем энергопотреблении?
В том и прикол, что гцц значение концепта (булевой константы) кеширует в лучшем виде.
В вот значение атомарного ограничения (но только для данного концепта) он иногда пересчитывает, а иногда кеширует. Переход с false на true он диагностирует, а в обратную сторону - не догадался. Надо будет им зарепортить, уж больно смешной недочёт. Они не предполагали, что ограничение может откатываться.
Есть разные способы откатить ограничение вида `requires{ f(x); }`.
явно запретить наилучшую сигнатуру, `= delete`
добавить конкурирующие сигнатуры, чтобы нельзя было выбрать наилучшую
какой-то ещё способ я случайно нашёл, когда писал статью, но сейчас что-то не могу вспомнить
Ещё замечание.
Во-первых, у конструктора (конструкторов) может быть более одной перегрузки. Поэтому Reflect<T> по-хорошему должен был бы отдавать не один кортеж типов, а набор кортежей.
Во-вторых, если конструктор содержит шаблонные аргументы, то Caster сработает криво. Либо конструктор примет его как родного, либо не примет вообще, потому что это будет считаться двойным неявным приведением.
В-третьих, если конструктор принимает initializer_list, - то получится странное
В-четвёртых, явно объявленные стандартные конструкторы - копирования/перемещения - добавят угару. Даже если они =default.
В общем, техника имеет ряд ограничений, либо её надо допиливать и тестировать на всём безумном сочетании условий.
Тут затесалась ошибка, делающая даже не UB, а IFNDR.
Во-первых, шаблонная константа kTest инстанцируется в точке первого использования - и далее переиспользуется. Поэтому
не прокатит. Либо первый ассерт упадёт, либо второй.
Во-вторых, https://timsong-cpp.github.io/cppwp/temp.constr.constr#temp.constr.atomic-3.sentence-5
Даже если мы будем перезапрашивать выражение у данной шаблонной функции
или чтоб совсем по-хитрому
то нарушим указанный пункт стандарта.
Вот можете полюбоваться
https://habr.com/ru/articles/857744/
Чиселки я привёл лишь затем, чтобы явно показать разные воплощения шаблона.
На самом деле, противоядие от "the satisfaction result is different for identical atomic constraints" состоит в том, чтобы сделать ограничения не идентичными. Для этого и надо пропихнуть переменный параметр шаблона внутрь.
Трюк с неявным уникальным параметром шаблона - а каждая лямбда уникальна - это дополнительный уровень. В первую очередь, чтобы не писать чиселки. Чтобы каждое воплощение шаблона было новым. Но в любом случае, придётся упоминать его внутри requires.
Но мне кажется, что это плохая практика для больших программ. Как минимум, это приведёт к размножению воплощений. Сведём с ума сперва компилятор, а затем линкер...
Разве что как тест на ill-formed (godbolt):
Вещественный остаток - это всё те же игры с округлением, только спрятанные под капот.
Так что не считается!
В куске гипса квадратное делается элементарно. Опалубка из досок, по-вашему, какая проще? А мелкие отверстия - ну, возьмите брусок и ткните в гипс до того, как он схватится.
"За N комментов до Гитлера"
Но кстати, как раз Гитлер сперва настаивал на фрактуре, а потом передумал и стал настаивать на антикве.
Вы хорошо понимаете теорию погрешностей?
А если программист, который сравнивает вещественные числа, как раз хорошо понимает, и следит за наличием-отсутствием погрешностей в своём коде? У него будет результат ХЗ? Или это у вас будет мнение ХЗ о его результате?
Давайте начнём с самого простого: 0.5 == 1.0 / 2.0, тут хз или не хз?
Хахаха, автор написал статью про джунов, а тут к нему набежали сеньоры, которые ещё и в теории погрешностей разбираются.
Кстати о погрешностях.
Знаете такую штуку, как функция линейной интер/экстраполяции?
lerp(x, y, r) = x + (y-x) * r
lerp(x, y, 0) = x
lerp(x, y, 1) = y
Казалось бы, что может пойти не так? А много что. Ошибка нормализации разности, и вжух, lerp(x,y,1) > y.
Правильный способ описан, например, вот тут:
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0811r3.html
а в std::lerp для вещественных чисел даже используется FMA вместо отдельного умножения и сложения.
Тем не менее, банковское округление и округление от нуля - это тоже традиционные. В том смысле, что используются на практике, а не добавлено "с потолка", лишь бы было.
Поскольку "к ближайшему целому" неоднозначно для полуцелых чисел, то опытный кодер обязательно уточнил бы у собеседующего, чего именно тот хочет. А заодно и рассказал бы и про три самых популярных.
Тут, конечно, для собеседующего может прозвенеть красный звоночек overqualified, "чего это я собеседую на позицию джуна, а ко мне пришёл то ли мидл (а то и сеньор), то ли лютый зануда..."
Всё-таки, навевает огромной печалью от того, что авторы эзолангов упарываются на тему вычурного синтаксиса, но очень неглубоко. Тупейшими макроподстановками можно вычистить весь код, превратив его в какой-нибудь базовый брейнфак, форт или бейсик.
Малболге хотя бы подкинул головняка.
Я уже и забыл про их существование... Ну, помянем.
1) Административное решение. Не принимать библиотеку в ветку qa-checked или как оно там называется в вашем репозитории. А если прямо совсем мешает разработке, то отревертить в вашей основной ветке - мастер/транк/как оно там называется.
Пусть техлид отведёт фичную ветку, где займётся миграцией на новую версию библиотеки в спокойном режиме.
Как вообще можно было вмержить в мастер эпохальное изменение, минуя тесты? Или часть библиотек живёт вне репозитория? Ну хотя бы докерфайл же должен жить в репе? Значит, надо переделывать, чтобы системные зависимости тоже там оказались.
2) Выкиньте свой boid, вы рискуете отхватить проблемы в самых неожиданных местах, где будет делаться проверка на void / не-void. Потому что вжух, и там окажется не-void.
Кстати, зачем у boid конструктор от более чем одного аргумента, да ещё и с приплясыванием "кроме наследников boid"? Чую, у вас там где-то говнокод с оператором запятая притаился, который оказался вовсе не оператором...
А не хотите ли проверить, что где-то запятая ведёт себя не так, как вы ожидаете?
3) Специализация / if-constexpr в общем случае, плюс разные техники scope guard там, где они применимы.
4) Фактически, вам очень жирно подсветили, что именно ваша обвязка не умеет работать с void. Заодно проверьте, умеет ли она корректно работать с другими разнообразными типами. Ссылочные, некопируемые, неполные, - вот это всё.
Вот прямо сходу бросается в глаза:
Локальная переменная по значению, и возврат по значению. Знаете, сколько граблей тут рассыпано? Часть из них можно было бы убрать с помощью
decltype(auto)
.5) Юниттесты на вашу библиотеку тестов есть? Они покрывают это разнообразие?
На списках - сам бог велел слиянием сортировать. Это даёт гарантии на логлинейное время.
Настоящий квиксорт на массиве - тоже неустойчивый.
Минус пирамидальной сортировки - в том, что она в лучшем случае вдвое медленнее быстрой (элементы сравниваются и перемещаются дважды - при сборке и разборке кучи).
А вот плюс - в том, что она гарантирует логлинейное время.
Промышленные методы сортировки - это сплав быстрой, вставок и пирамиды.
если массив маленький, то вставками он сортируется быстрее, просто потому, что два цикла быстрее, чем рекурсии
если глубина рекурсии превысила порог, кратный логарифму длины массива, это признак того, что набор плохой для квиксорта, и надо валить оттуда, пока мы до квадрата не доигрались, - запускают пирамиду
А потому что халява сэр. Ещё бы на хаскелле написали, там синтаксического шума примерно в пять раз меньше будет.
Сделать inplace quicksort на питоне - примерно столько же кода, как на яве, ну вдвое меньше строк за счёт фигурных скобок.
это шараханья туда-сюда.
с пикабу на реддит по случаю любого первого попавшегося бунда
с реддита на пикабу по случаю любого невменяемого модерирования
История реддита показывает, что как только аудитория оказывается достаточно лакомым куском для Очень Больших Политиков, они захватывают инициативу и устраивают там филиал демпартии США.
А, упс. Ну в таком случае для некоторых n решения тупо нет.