Комментарии 8
Хранить в одном контейнере разнотипные объекты можно (например, использовать std::variant или динамический кортеж), но в нашем случае довольно накладно.
На всякий случай добавлю, что boost::any_range не бесплатен, он выделяет динамическую память и использует виртальные функции, вряд ли дешевле variant'а.
Справедливо. Надо бы замерить.
Предварительные результаты замеров в попугаях:
Обычные итераторы: 26
boost::any_iterator: 215
variant_iterator (самописный): 32
Также эксперементирую самописным any_iterator без виртуальных фунций, но быстрее пока не выходит.
А как может быть any_iterator без виртуальных функций? Тогда он должен знать все типы, которые он должен затайперэйзить, а это уже не будет any_iterator. Концептуально, по моему, быстрее варианта ничего не получится. Из-за знания типов итераторов исходных рэнжей на этапе компиляции можно избавиться от динамической аллокации, а вместо виртуальных функций - switch по типу, который стоит примерно как виртуальный вызов.
Без виртуальных функций можно делать через механизм обобщённых обработчиков. Писал об этом тут: https://habr.com/ru/post/302372/#manager
Или можно посмотреть реализацию std::function в любой современной стандартной библиотеке.
Но это ничем не отличается от std::vaiant по производительности, но нужо знать конкретные классы, то есть ваш any_iterator Будет шаблоном, а весь сок в том, что это не шаблон.
Нет, типы знать не нужно. Шаблоном не будет :). Ну то есть будет, но параметры — не итераторы, а тип значения и категория.
Как-то так это можно сделать: https://pastebin.com/Z6wemSjB
Ленивые диапазоны и стирание типов