(переменная hidden — просто для проверок, что класс инициализирован)
Привязка его к daScript:
..и добавление в модуль
определение ManagedStructureAnnotation выглядит как:
Это структура разбирает данные о типе OT с помощью std::type_traits и устанавливает его свойства, на основе которых daScript знает, что можно/нельзя делать с типом.
Пока всё тривиально, MyClass — standart layout структура, не требующая дополнительной инициализации.
Попробуем добавить в класс что-нибудь, что потребует его инициализации:
Байндинг класса при перекомпиляции “увидит”, что теперь класс нетривиальный, и правильно переопределит его свойства. Теперь класс не может быть локальным, не может быть скопирован или перемещён:
Соотвественно, тот же код на daScript выдаст ошибки компиляции, при попытке создать класс без инициализации:
daScript достаточно консервативно определяет, что объект нельзя копировать/перемещать, вообще говоря, если у класса есть конструктор копирования, то его можно разрешить копировать, если просто явно переопределить функцию canCopy в аннотации-обёртке класса
Если можно построить объект из другого объекта, то можно и copy/clone/move?
Также в unsafe блоке теперь можно делать небезопасные, но интересные штуки:
компилятор начнёт ругаться на то, что не определён шаблон cast_arg<MyClass>::to. daScript-функции представляют свои аргументы и результаты в виде 128-битного типа vec4f, так что для кастомных типов необходимо описать способ преобразования с помощью частичной специализации этого шаблона.
Другие примеры возможных способов определения преобразования:
Из пары примеров выше видно, что для привязки функций, возвращающих тип в качестве результата, необходимо определить специализацию шаблона cast_res с функцией from. Это верно для standard layout структур, но для сложного класса (с созданием временного объекта на хипе, по аналогии с sf::String) daScript бросает assert:
говорит этот ассерт о том, что вместо того, чтобы создавать временный объект, что тормознуто, лучше использовать специальную ноду языка, которая возвращает уже созданный объект. Такое себе принуждение к оптимизации.
Вся эта шаблонная магия привязок генерится не руками, а генератором привязок dasClangBind. Распознавание инфы о типах сделано на уровне самого кода daScript, а не генератора, чтобы сам код генератора и сгенерированный код был более простым и однообразным. Но все примеры обёрток, сделанные dasClingBind, сделаны для библиотек с C-интерфейсом, которые почти не требуют ручного вмешательства. Но как только дело доходит до реального C++ кода, вылезает всё и сразу. Описанные в статье приёмы позволяют побороть большую часть сложности, и нагенерировать что-нибудь серьёзное, типа привязок классов Unreal Engine (с небольшими доработками напильником).
Примеры привязок либ с c-интерфейсом через dasClangBind:
Другие подходы: Automatic Language Bindings — размышления о способах генерации привязок к языкам от автора sokol gfx (тоже c-style, с помощью clang json) Using C Libraries in Zig — прозрачный импорт C из zig. с Си (не С++) вообще все достаточно просто Binding Nim to C++ std::list — читерский подход в nim, без интерпретации и с транспиляцией в C++ можно просто встраивать и использовать куски плюсового кода. Circle — “бэтменский” альтернативный компилятор с встроенными compile-time фичами, включая рефлексию. Автор публикует прогресс в твиттере cppyy: Automatic Python-C++ bindings — хардкор с использованием интерактивного компилятора C++ cling, прозрачный парсинг, компиляция и генерация привязок на лету