Comments 19
Чем Вам не подошла реализация того же самого в Qt (http://www.qt.io/)?
+1
Да, Qt-шный moc похож на мое решение. С Qt работал уже давно и беглый обзор их решения мне не понравился по нескольким причинам: нет доступа к членам класса, нет атрибутов, нельзя добавить своего функционала. Для меня просто не хватило тех функций что дает Qt. Еще, мой проект подразумевается коммерческим, а тянуть за собой Qt или его часть — совсем не вариант.
0
нет доступа к членам класса, нет атрибутов
Есть атрибуты http://doc.qt.io/qt-5/qobject.html#Q_PROPERTY
Для меня просто не хватило тех функций что дает Qt.
Расскажите более конкретно чего не хватает, просто интересно.
Еще, мой проект подразумевается коммерческим, а тянуть за собой Qt или его часть — совсем не вариант.
Почему? Там лицензия LGPL.
0
Есть атрибуты doc.qt.io/qt-5/qobject.html#Q_PROPERTY
Хм, я подумал это что-то вроде properties из C#… Но даже так, для меня это выглядит довольно резко — заворачивать все члены класса в макрос. Такое у меня требование — минимум вмешательства в синтаксис.
Расскажите более конкретно чего не хватает, просто интересно.
Мне нужны свои собственные атрибуты, которые могут нести какую-нибудь информацию. Мне нужен доступ к членам класса: запись и чтение. Мне нужно находить член класса в иерархии объектов по его пути. Для функций мне нужно их название, возвращаемый тип, список аргументов. Мне нужна информация о наследовании.
Почему? Там лицензия LGPL.
Дело даже не в лицензии, а в том, что я не хочу делать так сказать "франкинштейна". Если есть возможность реализовать модуль самому в короткие сроки — я выберу этот путь.
0
У класса QObject есть метод:
Посмотрите его описание, там много интересного http://doc.qt.io/qt-5/qmetaobject.html
const QMetaObject * QObject::metaObject() const
Посмотрите его описание, там много интересного http://doc.qt.io/qt-5/qmetaobject.html
0
Значимые комментарии — это ад, никогда так не делайте.
Хотите сделать аттрибуты, которые понимает внешний парсер? Используйте пустой макрос типа #define custom_attributes(...)
Хотите сделать аттрибуты, которые понимает внешний парсер? Используйте пустой макрос типа #define custom_attributes(...)
+7
Спасибо за подсказку! В следующих версиях так и сделаю.
0
Значимые комментарии — это ад, никогда так не делайте
А в чём там могут быть проблемы?.. Вроде, doxygen использует такой подход.
0
В C++11 можно еще попробовать использовать нативные аттрибуты (ака [[ deprecated ]]). Преимущество в том, что там хорошо описано, где они могут встречаться и к чему относиться. Если компилятору неизвестен аттрибут, то он его игнорирует с варнингом. Весь вопрос в том, как дополнить какой-нибудь clang плагином, который их читает. Такой информации в интернете не нашел.
0
А чем для парсинга clang не подошёл?
+1
В начале, мне это показалось довольно монструозным решением. Как из пушки по воробьям. Своя реализация заняла примерно неделю, а с clang неделю бы только разбирался. Хотя сейчас, видя все проблемы с утилитой кодогенерации, использование clang не кажется плохой идеей.
0
Своя реализация заняла примерно неделю
Мм… Полный парсер С++? Со всем его шаблонным адом и одиннадцатым стандартом? За неделю?.. Очень круто, если это вышло! Респект.
0
О нет, что вы… Минимум для того чтобы сгенерировать инициализацию типов. Конечно, пришлось повозиться с шаблонами, typedef, макросами и т.д.
0
А что такое "сгенерировать инициализацию типов"? Как я понимаю, это вытащить информацию об объявленных в классах полях и их типах? Но это ведь всё равно достаточно полный парсинг языка — нехилая часть работы.
Бывают ведь переменные, объявленные вперемешку с методами (значит нужно уметь игнорировать методы — включая реализованные в хедер-файлах), бывают всякие стрёмные варианты вроде инлайн-объявленных типов (например, анонимных): struct { int x; int y; } _vectorField… Да и шаблоны, обратно, парсить радость ещё та — особенно с учтём всяких boost-style, рекурсивных...
Да, вспомнил, типы ведь ещё часто генерируют из макросов — видел в нескольких проектах, включая последний игровой проект, с которым имел дело. Это ведь тоже нужно обрабатывать, верно? Если ваш парсер умеет всё это — он крут.
П.С.: А на чём писали, кстати?
Бывают ведь переменные, объявленные вперемешку с методами (значит нужно уметь игнорировать методы — включая реализованные в хедер-файлах), бывают всякие стрёмные варианты вроде инлайн-объявленных типов (например, анонимных): struct { int x; int y; } _vectorField… Да и шаблоны, обратно, парсить радость ещё та — особенно с учтём всяких boost-style, рекурсивных...
Да, вспомнил, типы ведь ещё часто генерируют из макросов — видел в нескольких проектах, включая последний игровой проект, с которым имел дело. Это ведь тоже нужно обрабатывать, верно? Если ваш парсер умеет всё это — он крут.
П.С.: А на чём писали, кстати?
0
Вот мне интересно, а что мешает вне зависимости от всяких метатэгов вроде IOBJECT взять и обойти сторонней тулой (которая как кастом тул запускается) обойти весь вообще код и просто вставить (физически) метаданные в каждый из файлов, или например взять и вынести их в отдельную компоненту чтобы вызывать что-то вроде
Type::Of<Something>
и иметь на нем .fields
, .functions
и так далее?0
Все не так просто.
Как в таком месте должна работать тулза без интеграции с компилятором? А как насчет
Так что пока надежда только на рефлексию в C++17 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4451.pdf или костыли (коих десятки).
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 или костыли (коих десятки).
0
То что вы привели в пример – это достаточно экстремальный кейс, в то время как обычна рефлексия – это взять
Typeof<T>::fields
текущего класса, нарпимер. То есть можно специализировать T → Foo, подставлять Foo
и все должно работать. (И, точно так же, если у вас нет рефлексии для типа Bar
, ваша программа не скомпилируется.)0
Рефлексия в С++ вообще вещь интересная, и поле непаханное для всяких извращений.
Что-то вспомнилось как мы ради смеха делали что-то типа JUnit для С++. Стандартный CPPUnit не очень нам понравился так как требовал много лишних макросов и ручной работы по регистрации методов.
Рефлексия (то есть нужно взять объект и вызвать по очереди у него все методы-тесты) у нас достигалась итерацией по таблице виртуальных функций. Указатель на ее начало-то получить просто, сложно понять где надо остановиться. Для этого с помощью некоторых ухищрений создавалась виртуальная функция, которая в таблице всегда оказывалась последней, и устанавливала флаг что дальше идти не надо.
В итоге достаточно при определении тестового класса достаточно было использовать один макрос, а затем просто все тестовые методы объявить виртуальными. И вуаля, они все вызывались автоматически. Почти как в джаве. Никакой ручной регистрации, кодогенерации, ничего лишнего.
Решение конечно было кривое и хакнутое донельзя, зависело от компилятора и того как он обрабатывал таблицу виртуальных функций. Зато тестовый код красиво выглядел в итоге.
Что-то вспомнилось как мы ради смеха делали что-то типа JUnit для С++. Стандартный CPPUnit не очень нам понравился так как требовал много лишних макросов и ручной работы по регистрации методов.
Рефлексия (то есть нужно взять объект и вызвать по очереди у него все методы-тесты) у нас достигалась итерацией по таблице виртуальных функций. Указатель на ее начало-то получить просто, сложно понять где надо остановиться. Для этого с помощью некоторых ухищрений создавалась виртуальная функция, которая в таблице всегда оказывалась последней, и устанавливала флаг что дальше идти не надо.
В итоге достаточно при определении тестового класса достаточно было использовать один макрос, а затем просто все тестовые методы объявить виртуальными. И вуаля, они все вызывались автоматически. Почти как в джаве. Никакой ручной регистрации, кодогенерации, ничего лишнего.
Решение конечно было кривое и хакнутое донельзя, зависело от компилятора и того как он обрабатывал таблицу виртуальных функций. Зато тестовый код красиво выглядел в итоге.
+5
Sign up to leave a comment.
Рефлексия и кодогенерация в C++