Комментарии 15
using OpVariant = std::variant<AddOp, MulOp, XorOp>;
std::vector<OpVariant> data;
...
if (i % 3 == 0) data.push_back(std::make_unique<AddOp>());
else if (i % 3 == 1) data.push_back(std::make_unique<MulOp>());
else data.push_back(std::make_unique<XorOp>());против:
using OpVariant = std::variant<AddOp, MulOp, XorOp>;
std::vector<OpVariant> data;
...
if (i % 3 == 0) data.push_back(std::make_unique<AddOp>());
else if (i % 3 == 1) data.push_back(std::make_unique<MulOp>());
else data.push_back(std::make_unique<XorOp>());Автор - писатель, а не читатель. Вычитка где? В чём разница этих одинаковых инвалидных блоков? И в чём состоит сакральный смысл многоточий?
Исправил. Спасибо! По этой статье образовалось бесконечное количество материалов, не там вычитывал, видимо, запутался.
Всё ещё инвалидный код после правки.
Многоточия только засоряют код. Это так важно показать, что что-то ещё там может быть?
Но это уже субъективно, вам не кажется? Получается что для вас очень важно что это не важно, или, другими словами, чтобы я сделал так, как хочется именно вам. Но если я буду делать то, что кому-то хочется, то боюсь, от меня самого ничего не останется. Надеюсь вы это тоже понимаете.
(динамическое время жизни, тяжелые объекты, раздельная компиляция модулей)
Или, что бывает довольно часто, тяжелые объекты из подключаемых библиотек.
Вообще этот вот ваш variant мне не очень понятен именно для интерфейсов - он предпологает, как старый добрый union, что вся эта вот вариативность - она тут, в доступных в этом модуле структурах. И использовал бы я её только когда есть данные и разные стили их интерпретации: ну пакет байтов обрабатываем там, или что-то подобное. Для всего прочего всё равно надо писать класс-обёртку с методами, возвращающими нужный объект, и в таком случае что там под капотом - variant, полиморфизм или тупо кастинг - становится уже не важно. А класс писать придётся - рано или поздно, при развитии проекта, чистый полиморфизм растворится и общность этих вот объектов станет несколько натянутой, если вообще возможной. И тогда ты или пишешь класс-конвертор для всех, или по одному для каждого объекта, чтобы привести его обратно к интерфейсу.
Вы абсолютна правы!) Этот вопрос затрагивает саму суть! Любое утверждение про производительность какого-либо кода просто болтовня, пока не сделаны бенчи.
Как меняется ситуация если попытаться зафиналить наследование? Что насчет поднятия стандарта до 20 и перехода на концепты вместо наследования, ну или при помощи SFINAE? Ну и отдельный вопрос насколько отличается время компиляции для разных вариантов?
По поводу ИИ умника. Попросил оптимизировать небольшую функцию, явно указав, что оптимизирвоать скорость работы, для уменьшения времени выполнения. ИИ сильно код переделал, выглядело красиво и заумно и ИИ в примечании утверждал, что это самое производительное решение. Из плюсов, результат работы был правильный. Из минусов, работало в 15 раз медленнее наивной реализации в лоб. О2 компиляция, разумеется.
Автор доблестно победил (убедил) ИИ в том что он прав и на самом деле variant всегда был плохим. Всё что за статью написано: надо зачем то сломать весь смысл variant и засунуть в него unique_ptr
В этом и смысл variant, что ему не нужно выделять память для "полиморфности". Логичнее было бы пойти наоборот и убрать выделение памяти в случае с виртуальными функциями
прочно укоренилось мнение: классический динамический полиморфизм через виртуальные функции (
vtable) и наследование — это устаревший, медленный и недружелюбный к кэшу процессора механизм
это мнение только у тех, кто не понимает как устроено ни одно, ни другое. В качестве учебного упражнения советую написать std::visit (хотя бы для одного variant) и vtable
В этом и смысл variant, что ему не нужно выделять память для "полиморфности". Логичнее было бы пойти наоборот и убрать выделение памяти в случае с виртуальными функциями
я подозреваю, что тогда разницы на уровне машинных кодов (ассемблера) вообще не будет, оба варианта превратятся в switch? Или есть варианты?
— Вы написали и запустили бенчмарк?
— Лучше! Я спросил ИИ что будет если запустить бенчмарк!
Кроме "запустить бенчмарк" надо еще хорошо понимать как интерпретировать результаты этого бенчмаркака. Какой смысл запускать бенчмарк, если его результатам нельзя доверять? Если можно произвольно менять (подкрутить) внешние условия и получить любые "правильные" результаты?
Бенчмарк (эксперимент) имеет смысл только когда есть теория, которую он должен подтвердить или опровергнуть. Я не претендую на то, что я сформулировал верную теорию или что мои аргументы совершенно корректны! Отчасти, я лишь хочу продемонстрировать какая работа должна предшествовать подобного рода экспериментам.

Динамический полиморфизм против std::variant с указателями: Разрушаем мифы о скорости std::visit (v.2*)