Comments 6
Вызвана ли необходимость написания руками данного довольно сложного кода отсутствием рефлексии в плюсах?
Вы писали, что при разыменовании получаем char* либо const char*. В рамках рассматриваемой ситуации в полях хранятся только примитивы всегда?
Добрый день!
Да, если бы была рефлексия, можно было бы перевести код на неё. Не думаю, что он бы стал сильно проще в итоге: поскольку речь о передаче данных в т. ч. по сети и в модули на других языках, к собственно плюсовому представлению данных привязываться нельзя.
Да, только примитивы - возможна передача по сети. Представление строк показано, представление массивов аналогично, вместо объектов передаются хэндлы, которые можно затем использовать для вызова.
Решал подобную задачу на языке с рефлексией. Если типов пакетов не много, то проще фигачить итераторы по входящему потоку байт.
Если типов пакетов много, то придётся городить разметки пакетов - очерёдность полей и тп. Плюс налету генерировать код паркинга, чтобы каждый раз рефлексию не дёргать. Не факт, такой подход будет более читаемым и поддерживаемым.
рефлексия, когда имена полей можно игнорировать, в современных плюсах уже есть
"Но зачем?" (c)
В смысле, достаточно интересно, но лично мне гораздо проще придумать, как такое реализовать, чем как использовать (кроме сериализации – мыслей вообще не возникло, но в ней итератор, возвращающий поля разных типов, как-то не особо нужен). И, соответственно, была бы интересней не статья про реализацию, а статья про постановку задачи, потребовавшую такого.
Вот здесь я описывал архитектуру разрабатываемой системы, в которой ядро взаимодействует с локальными модулями, а также другими ядрами по сети при помощи вот таких бинарных пакетов. Структуру самих пакетов как-нибудь опишу более подробно.
Если вкратце - на основе API метода (оторванного от языка) формируется соглашение о раскладке полей аргументов и возвращаемых значений. Затем ядро пакует данные с использованием описанного итератора и передаёт модулю, а тот распаковывает - либо с использованием тех же итераторов (если используется C++ SDK), либо самостоятельно (есть пример модуля на чистом C, который просто приводит полученный void* к указателю на соответствующую структуру). И наоборот: модули пакуют данные, ядро - распаковывает. Получилось лаконичнее, чем если бы на каждый метод была своя структура данных (как у GRPC, к примеру).
Работа с void* в стиле C++