Pull to refresh

Comments 19

Чем Вам не подошла реализация того же самого в Qt (http://www.qt.io/)?
Да, Qt-шный moc похож на мое решение. С Qt работал уже давно и беглый обзор их решения мне не понравился по нескольким причинам: нет доступа к членам класса, нет атрибутов, нельзя добавить своего функционала. Для меня просто не хватило тех функций что дает Qt. Еще, мой проект подразумевается коммерческим, а тянуть за собой Qt или его часть — совсем не вариант.
нет доступа к членам класса, нет атрибутов

Есть атрибуты http://doc.qt.io/qt-5/qobject.html#Q_PROPERTY

Для меня просто не хватило тех функций что дает Qt.

Расскажите более конкретно чего не хватает, просто интересно.

Еще, мой проект подразумевается коммерческим, а тянуть за собой Qt или его часть — совсем не вариант.

Почему? Там лицензия LGPL.
Есть атрибуты doc.qt.io/qt-5/qobject.html#Q_PROPERTY

Хм, я подумал это что-то вроде properties из C#… Но даже так, для меня это выглядит довольно резко — заворачивать все члены класса в макрос. Такое у меня требование — минимум вмешательства в синтаксис.

Расскажите более конкретно чего не хватает, просто интересно.

Мне нужны свои собственные атрибуты, которые могут нести какую-нибудь информацию. Мне нужен доступ к членам класса: запись и чтение. Мне нужно находить член класса в иерархии объектов по его пути. Для функций мне нужно их название, возвращаемый тип, список аргументов. Мне нужна информация о наследовании.

Почему? Там лицензия LGPL.

Дело даже не в лицензии, а в том, что я не хочу делать так сказать "франкинштейна". Если есть возможность реализовать модуль самому в короткие сроки — я выберу этот путь.
Значимые комментарии — это ад, никогда так не делайте.

Хотите сделать аттрибуты, которые понимает внешний парсер? Используйте пустой макрос типа #define custom_attributes(...)
Спасибо за подсказку! В следующих версиях так и сделаю.
Значимые комментарии — это ад, никогда так не делайте

А в чём там могут быть проблемы?.. Вроде, doxygen использует такой подход.
doxygen всё таки документацию генерит а не код, по ним (собственно комментарии и являются документацией)
а генерит код, по комментам — это зло
В C++11 можно еще попробовать использовать нативные аттрибуты (ака [[ deprecated ]]). Преимущество в том, что там хорошо описано, где они могут встречаться и к чему относиться. Если компилятору неизвестен аттрибут, то он его игнорирует с варнингом. Весь вопрос в том, как дополнить какой-нибудь clang плагином, который их читает. Такой информации в интернете не нашел.
В начале, мне это показалось довольно монструозным решением. Как из пушки по воробьям. Своя реализация заняла примерно неделю, а с clang неделю бы только разбирался. Хотя сейчас, видя все проблемы с утилитой кодогенерации, использование clang не кажется плохой идеей.
Своя реализация заняла примерно неделю

Мм… Полный парсер С++? Со всем его шаблонным адом и одиннадцатым стандартом? За неделю?.. Очень круто, если это вышло! Респект.
О нет, что вы… Минимум для того чтобы сгенерировать инициализацию типов. Конечно, пришлось повозиться с шаблонами, typedef, макросами и т.д.
А что такое "сгенерировать инициализацию типов"? Как я понимаю, это вытащить информацию об объявленных в классах полях и их типах? Но это ведь всё равно достаточно полный парсинг языка — нехилая часть работы.
Бывают ведь переменные, объявленные вперемешку с методами (значит нужно уметь игнорировать методы — включая реализованные в хедер-файлах), бывают всякие стрёмные варианты вроде инлайн-объявленных типов (например, анонимных): struct { int x; int y; } _vectorField… Да и шаблоны, обратно, парсить радость ещё та — особенно с учтём всяких boost-style, рекурсивных...

Да, вспомнил, типы ведь ещё часто генерируют из макросов — видел в нескольких проектах, включая последний игровой проект, с которым имел дело. Это ведь тоже нужно обрабатывать, верно? Если ваш парсер умеет всё это — он крут.

П.С.: А на чём писали, кстати?
Вот мне интересно, а что мешает вне зависимости от всяких метатэгов вроде IOBJECT взять и обойти сторонней тулой (которая как кастом тул запускается) обойти весь вообще код и просто вставить (физически) метаданные в каждый из файлов, или например взять и вынести их в отдельную компоненту чтобы вызывать что-то вроде Type::Of<Something> и иметь на нем .fields, .functions и так далее?
Все не так просто.

template<class T>
auto first_field(T arg) {
   return Type::Of<T>.fields[0];
}

Как в таком месте должна работать тулза без интеграции с компилятором? А как насчет Type::Of< std::result_of_t<func(TypeOf<T>.fields[0])> >?

Так что пока надежда только на рефлексию в C++17 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4451.pdf или костыли (коих десятки).
То что вы привели в пример – это достаточно экстремальный кейс, в то время как обычна рефлексия – это взять Typeof&lt;T&gt;::fields текущего класса, нарпимер. То есть можно специализировать T → Foo, подставлять Foo и все должно работать. (И, точно так же, если у вас нет рефлексии для типа Bar, ваша программа не скомпилируется.)
Рефлексия в С++ вообще вещь интересная, и поле непаханное для всяких извращений.
Что-то вспомнилось как мы ради смеха делали что-то типа JUnit для С++. Стандартный CPPUnit не очень нам понравился так как требовал много лишних макросов и ручной работы по регистрации методов.
Рефлексия (то есть нужно взять объект и вызвать по очереди у него все методы-тесты) у нас достигалась итерацией по таблице виртуальных функций. Указатель на ее начало-то получить просто, сложно понять где надо остановиться. Для этого с помощью некоторых ухищрений создавалась виртуальная функция, которая в таблице всегда оказывалась последней, и устанавливала флаг что дальше идти не надо.

В итоге достаточно при определении тестового класса достаточно было использовать один макрос, а затем просто все тестовые методы объявить виртуальными. И вуаля, они все вызывались автоматически. Почти как в джаве. Никакой ручной регистрации, кодогенерации, ничего лишнего.

Решение конечно было кривое и хакнутое донельзя, зависело от компилятора и того как он обрабатывал таблицу виртуальных функций. Зато тестовый код красиво выглядел в итоге.
Sign up to leave a comment.

Articles