Как стать автором
Обновить

Комментарии 19

Мне вот лично больше по душе compile-time рефлексия. С помощью неё можно при желании и runtime навелосипедить, но она не вносит никакого оверхеда в процессе исполнения, если ей не пользуешься. В отличии от rtti, которая в любом случае скушает память, будешь ты делать касты или нет.

Ну, иногда compile time не обойтись. Как, например, по строковому имени (либо по идентификатору) создать объект класса, пользуясь compile time-рефлексией? А это нужно минимум для сериализации.

Фреймворки, заменяющие RTTI, используются как раз для того, чтобы получить предсказуемый RTTI только для некоторых классов, для которых нужен механизм RTTI (в отличие от стандартного RTTI).

Конструировать статический std::map/unordered_map/concurrent_map/mysuper_map в удобном для задачи формате из compile-time информации ровно там, где это нужно.

Да, у меня была подобная идея. Но потом я подумал, что это решение почти эквивалентно тому, что я написал. Единственный overhead на регистрацию классов при старте программы, который, как мне кажется, можно не учитывать для сколь нибудь сложной программы.

Написать функцию, которая по compile time данным вызовет нужный конструктор. При наличии compile time рефлексии и шаблонов, можно сделать runtime рефлексию в любом удобном виде практически забесплатно. Вот пример как выпилить к чертям Qtшный moc, заменив его на рефлексию.
https://woboq.com/blog/reflection-in-cpp-and-qt-moc.html


Увы, но в стандарт её так и не взяли. Но мне кажется, что нужно именно в этом направлении двигаться. В принципе если устраивает сидеть только на clang'е (а это почти все оси на сегодня), то можно позвать libclang.
https://woboq.com/blog/moc-with-clang.html

cpprt не делает никакой магии в runtime. Принцип её работы следующий:

1. Выполнить регистрацию фабрик до старта main() за счёт вызова конструкторов этих же самых фабрик. Регистрация означает просто добавление в массив (считайте, в map).
2. Всё… Можно из этого массива через набор методов доставать информацию. Так же, как если бы был использован обычный массив (или map) фабрик, но обёрнутый в класс.

Это почти один-в-один похоже на все решения, которые тут предлагают с массивом фабрик и чуть медленнее решений, которые предлагаются со switch case (ведь вместо switch case будет обход мапы или массива).

Быстрее этого решения разве что решение, построенное на шаблонах, как это сделано с std::numeric_limits, где, фактически выполняется поиск нужной специализации шаблона. Тут я согласен, это будет быстрее, и я подумываю о том, как это можно встроить в библиотеку.
если устраивает сидеть только на clang'е

Почему? Можно ведь использовать libclang только для кодогенерации, а потом звать родной компилятор.
Как, например, по строковому имени (либо по идентификатору) создать объект класса, пользуясь compile time-рефлексией?

В простейшем варианте — при помощи switch/case или статического map<string,Factory>.
Так библиотека и хранит в себе что-то вроде map<string,Factory> (можете почитать первую статью о том, как это сделано). Библиотека просто даёт возможность через макросы описать нужную метаинформацию рядом с декларацией и реализацией классов.
Создание экземпляра класса вызовом factory, найденным по некоторому ключу в map, это не reflection. И для этого не нужны ни run-time, ни compile-time reflection.
В той же Java это относят к рефлексии, поэтому я тоже решил, что это можно назвать рефлексией. Я не претендую на большое количество предоставляемых метаданных, потому назвал статью «немного рефлексии для С++».
Нет, создание экземпляра класса при помощи factory не относится к reflection даже в Java. Это просто factory design pattern, который может использовать reflection, но в общем никак с ней не связан.
Ага… Ну хорошо, а получение информации об абстрактности классов или о их наследовании друг от друга?
Да. Инспекция, использование и модификация произвольных классов (даже неизвестных на момент компилирования) это reflection. Как и создание экземпляра класса таким способом (например, динамически нашли конструктор с нужной сигнатурой и вызвали его, подставив параметры).

Создание экземпляра класса через оператор new внутри factory (как и без factory) — нет.
cpprt позволяет получать информацию о наследниках классов. В принципе, можно прикрутить возможность добавлять и прочую метаинформацию.
Самая интересная фича в рефлексии это не получить имя класса, а получить список полей, их типы и офсеты. А создать фабрику типов можно и без рефлексии, с минимальным набором макросов.
Соглашусь. Тут есть некоторая терминологическая неточность. Я потому и назвал цикл «капелька рефлексии». По поводу списка полей и типов — этим занимается упоминаемая в статье «основная библиотека». Там используется обычное перечисление полей через вызовы методов save и load для объекты-сериализаторы. Я, увы, пока не довёл эту библиотеку до того вида, чтобы её можно было опубликовать.

А создать фабрику типов можно и без рефлексии, с минимальным набором макросов


Ну, в библиотеке и есть этот самый минимальный набор макросов.
Хорошо пишите. Рефлексия это хорошо… но двигаясь дальше вы все ближе подходите к необходимости второго .net (или java, кому как)?
Вот нет. Речь идёт как раз о том, чтобы иметь возможность добавлять метаинформацию только к тем классам, к которым она нужна (регистрировать классы), а не давать лишнюю информацию для всех классов, которые есть вообще.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории