В общем, эта классная идея не выгорела даже на этапе компиляции. Проблема в С++, в концепции инклюдов и forward-declaration'ах. Ему становится плохо от таких специализаций...
Дело в том, что если в .cpp не будет подключен .h, содержащий вашу частичную специализацию, то компилятор о ней и не узнает, и просто возьмет не специализированный шаблонный класс, и сделает его инстанс. То есть
Но еще больше проблем вызывает то, что пользователь может попросту забыть включить хидер со специализацией и получит неправильное поведение. То есть довольно легко отстрелить колено так, что не поймешь откуда прилетело.
Еще сильнее колено отстреливается когда в .h нет нужной специализации, а в .cpp она появляется. Здесь происходит откровенный пиздец, т.к. компилятор думает что класс определен с
Об этом писал в своей статье в предыдущем посте, что такой проблемы в принципе бы не существовало, будь у С++ другая стратегия компиляции, без инклюдов и форвардов.
Дело в том, что если в .cpp не будет подключен .h, содержащий вашу частичную специализацию, то компилятор о ней и не узнает, и просто возьмет не специализированный шаблонный класс, и сделает его инстанс. То есть
Ref<Actor>
заработает как обычный указатель, и не будет уметь сериализоваться/делать нужные штуки. Проблем добавляет цикличность зависимостей - class Actor
уже хочет знать о существовании специализации Ref<Actor>
, и приходится хитро форвардить. А так как в самом class Actor
тоже есть шаблонные методы, например Ref<T> FindActorByType<T>()
, то просто зафорвардить не получится, т.к. реализация функции в том же .h где и форвард, и компилятор ругается на отсутствие реализации Ref<T>
, который определен только forward'ом. Это решаемо, но через уродливые #include ""
посреди .h, что выглядит как минимум странноНо еще больше проблем вызывает то, что пользователь может попросту забыть включить хидер со специализацией и получит неправильное поведение. То есть довольно легко отстрелить колено так, что не поймешь откуда прилетело.
Еще сильнее колено отстреливается когда в .h нет нужной специализации, а в .cpp она появляется. Здесь происходит откровенный пиздец, т.к. компилятор думает что класс определен с
Ref<>
одного размера (8 байт на указатель), а реализацию функций с другим` Ref<>` (8 байт на указатель + 8 байт на вспомогательную инфу). В рантайме это выглядит как запись вне стека/участка памяти и шваркается рандомно. Слава господи address sanitizer сразу подсвечивает такие проблемы. Хотя разобраться в таком креше - это капец, абсолютно не понимаешь почему у тебя программа пытается писать за пределами объекта в конструкторе.Об этом писал в своей статье в предыдущем посте, что такой проблемы в принципе бы не существовало, будь у С++ другая стратегия компиляции, без инклюдов и форвардов.
и здесь я сразу решил с ноги зайти и просто написать что за тулзу я хочу. Да да, одним промтом, вот прям из коробки.
За основу я взял демо-проект imgui со своим прикрученным профайлером
Вот первый промт:
За основу я взял демо-проект imgui со своим прикрученным профайлером
Вот первый промт:
я хочу сделать графическую утилиту, которая сканирует исходники С++ в нескольких папках, строит зависимости, и отображает с помощью imgui в графическом виде эти зависимости. Графически эти зависимости кластеризуют связанные сущности (исходники), с помощью физических законов. Сущности представлены в виде цветных кружков, зависимости (или связи) в виде линий.
Зависимости строятся на 2х уровнях:
- иерархия папок и подпапок: для каждой директории создается сущность директории, дочерняя директория зависит от родительской. Внутри директории есть список сущностей - файлов в ней
- зависимости между исходниками С++ через #include: из каждого исходника парсится список инклюдов, ищутся файлы-исходники по путям и между ними создается связь
Работа физики:
- для этого сущности расположены в 2д мире, у каждого есть позиция
- между ними есть зависимости- связи, которые задают некое расстояние между сущностями
- сущности стараются оттолкнуться от билзлижащих сущностей
- используется интеграция верле и разрешение связей как в научной работе якобсена из hitman codename 47
- при зажимании левой кнопки мыши умеет захватывать сущность чтобы ее перемещать вслед за курсором
Графика:
- используется imgui Для отображения. В текущем исходнике Main.cpp создается дополнительное окно, в котором отображается вся графика: сущности и связи
- сущности - это разноцветные круги
- связи - это линнии между ними
- существует камера, которой можно управлять: скролл (перемещение) с зажатой правой кнопкой мыши, зум с помощью колесика
- наведение курсора на сущность включает ее подсветку: отображается имя исходника, а так же связь с родителем и детьми
- для профилирования используется nano profiler: работа физики и графики
что нужно сделать:
- завести json конфиг с параметрами: исходные директории для сканирования, настройки графики и физики. Работает как отдельный класс
- сделать класс парсера исходников с многопоточностью: берет исходные директории из json конфига и рекурсивно сканирует их в поисках C++ исходников .h/.cpp, парсит #include, связывает сущности, создает сущности для всех директорий
- физический движок, оптимизированный для вычисления 10000 сущностей и 30000 связей. Инициализируется из парсера исходников, сохраняя ссылки на исходные сущности. ПРоводит симуляцию мира и физики: интегрирует позиции, разрешает связи, расталкивает близлижащие сущности
- графическое отображение. Содержит камеру, обрабатывает инпут пользователя, отображает сущности и связи
- главный класс утилиты: читает конфиг, парсит исходники, инициализирует физику и графику, запускает игровой цикл апдейта фрейма - обонвление физики, обработка инпута и отрисовка
Разделяй вышеописанное на классы в разных файлах, рядом с Main.cpp. Используй для всего стандартную библиотеку stl и imgui. Не используй ничего кастомного, никаких скриптов, только С++
GitHub
GitHub - zenkovich/imgui_perfmon: Simple performance widget for ImGUI
Simple performance widget for ImGUI. Contribute to zenkovich/imgui_perfmon development by creating an account on GitHub.