Comments 33
Я наверное чего-то не понял. Где рефлексия-то? Имена полей как из структуры достать и их-же тип в виде строки к примеру получить? В упор рефлексии не вижу… Пойду очки куплю, для чтения…
-2
//offtopic
черные в дырочку…
черные в дырочку…
+1
А рефлексия это не обязательно строки. Это в первую очередь возможность, не глядя на типы, вытаскивать из объектов свойства. Да, в данном случае вытаскивать можно только по индексу. Но это уже даёт как минимум возможность итерироваться по полям произвольных структур, что уже достижение для C++.
Тема очень крутая, за текст +100500! Не так часто происходят такие открытия.
Тема очень крутая, за текст +100500! Не так часто происходят такие открытия.
Придирка к языку статьи
в русском языке используется «строка» кода, а не линия.
+4
Ну в таком случае в С++ уже давно рефлексия есть, кто запрещает сделать так:
class A
{
private:
int a, b;
...
}
void main()
{
A* a = new A();
int a_b = *(((int*)(a))+1);
...
}
-8
Какие открытия? Что вы за ерунду говорите? Хотя-бы в код nlohmann json, загляните, там этих открытий…
-5
Заглянул, не нашёл ничего, напоминающего рефлексию или автоматизацию. Как на основе обсуждаемой статьи сделать автоматическую сериализацию/десерализацию json я догадываюсь (хотя имена всё равно не вытащить, придётся делать ключами индексы и битовые представления типов). А в предложенном вами nlohmann json предлагается руками написать to_json и from_json.
+3
Прямо в README.md пример кода на C++:
Вобщем все те-же самые механизмы, что и в статье используются, только не так топорно и без криков об открытиях, и механизмов побольше чутка.
json j2 = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
Вобщем все те-же самые механизмы, что и в статье используются, только не так топорно и без криков об открытиях, и механизмов побольше чутка.
-3
У вас точно также нет рефлексии. Всё что вы делаете оно в compile time происходит. Ну о каких открытиях речь? Вот не вижу я их в упор. Перечислите, пожалуйста, что из механизмов C++11/14, используемых в статье, вы считаете открытием? Ещё можете сюда-же добавить typeid и type_info. И вообще будет мега-открытие.
0
Открытием я считаю возможность вот этого:
Да, это не runtime, это compile time reflection. От передаваемого value не требуется иметь специальные методы или перегружать специальные функции, или быть обработанным препроцессором. В то время как nlohmann json требует специальных методов.
Приведённый вами пример с json j2 = {...} создаёт объект типа json, а не типизированную структуру. Настоящая сериализация на основе рефлексии это что-то подобное:
Такое без препроцессора на C++ не сделать, но в статье показан приём, делающий нас на шаг ближе к желаемому. Имея итерацию по полям мы можем, потребовав каким-либо образом указать имена полей, решить задачу полностью.
flat_get<FieldIndex>(value);
Да, это не runtime, это compile time reflection. От передаваемого value не требуется иметь специальные методы или перегружать специальные функции, или быть обработанным препроцессором. В то время как nlohmann json требует специальных методов.
Приведённый вами пример с json j2 = {...} создаёт объект типа json, а не типизированную структуру. Настоящая сериализация на основе рефлексии это что-то подобное:
MyCustomStruct obj = from_json<MyCustomStruct>("{member1:12, member2:[0.0, 3.14]}")
Такое без препроцессора на C++ не сделать, но в статье показан приём, делающий нас на шаг ближе к желаемому. Имея итерацию по полям мы можем, потребовав каким-либо образом указать имена полей, решить задачу полностью.
+1
С какой радости «без препроцессора не сделать». И вообще, нет никакого открытия, — обращение к tuple с get делает ровно то-же самое, только не в рамках одной структуры. Внимание вопрос: В чём плюс обращения по номеру поля в структуре? Рефлексия требует человеко читаемых имён. Посмотрите в boost::multiindex, вот там рефлексия, там тегирование и имена индексов в compile time. А этот домострой вообще ни о чём.
0
Так в том и дело, что это не tuple, а любая структура. Преобразовать структуру в tuple не так-то просто без «этого домостроя». Можете предложить реализацию шаблона с таким объявлением?
Здесь Types… — список типов полей структуры T. Для любого конкретного типа всё тривиально, а обобщённо? В статье описано, как это сделать, а где ещё есть что-то подобное? Это и называется открытием — что-то, что до недавнего времени казалось невозможным, ну или никто подобного не делал.
boost::multiindex вообще мимо. Там тонны метапрограммирования, но к сабжу отношения не имеет.
template <typename T>
auto as_tuple(T&& t) -> tuple<Types...>;
Здесь Types… — список типов полей структуры T. Для любого конкретного типа всё тривиально, а обобщённо? В статье описано, как это сделать, а где ещё есть что-то подобное? Это и называется открытием — что-то, что до недавнего времени казалось невозможным, ну или никто подобного не делал.
boost::multiindex вообще мимо. Там тонны метапрограммирования, но к сабжу отношения не имеет.
0
UFO just landed and posted this here
man static reflection
0
И действительно — рефлексия это о runtime, а не compile time
-5
Есть рефлексия динамическая (run-time), есть статическая (compile-time).
C++ движется в сторону статической рефлексии www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0194r3.html
C++ движется в сторону статической рефлексии www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0194r3.html
+3
А если в структуре будет union?
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+4
Не нравится мне этот подход с индексированием базовых типов и побочным эффектом у оператора приведения типа. Можно сделать перечисление базовых типов в виде SFINAE специализации шаблона. Например:
Код
#include <iostream>
#include <tuple>
#include <typeinfo>
#include <utility>
namespace reflect {
namespace detail {
template <size_t>
struct ubiq {
template <class T>
constexpr operator T&() const;
};
template <class T>
struct exact {
constexpr operator T&() const;
};
template <class>
using void_t = void;
template <class T, size_t N = sizeof( T ), class S = std::make_index_sequence<N>, class = void>
struct tuple_size_helper : tuple_size_helper<T, N - 1, std::make_index_sequence<N - 1>> {
};
template <class T, size_t N, size_t... I>
struct tuple_size_helper<T, N, std::index_sequence<I...>, void_t<decltype( T{ubiq<I>{}...} )>> {
using type = std::integral_constant<size_t, N>;
};
} // namespace detail
template <class T>
using tuple_size = typename detail::tuple_size_helper<T>::type;
namespace detail {
template <size_t N, class T, class = std::make_index_sequence<N>, class = std::make_index_sequence<tuple_size<T>::value - N - 1>,
class = void>
struct tuple_element_helper;
template <size_t N, class T, size_t... I, size_t... J>
struct tuple_element_helper<N, T, std::index_sequence<I...>, std::index_sequence<J...>,
void_t<decltype( T{ubiq<I>{}..., exact<int>{}, ubiq<J>{}...} )>> {
using type = int;
};
template <size_t N, class T, size_t... I, size_t... J>
struct tuple_element_helper<N, T, std::index_sequence<I...>, std::index_sequence<J...>,
void_t<decltype( T{ubiq<I>{}..., exact<size_t>{}, ubiq<J>{}...} )>> {
using type = size_t;
};
template <size_t N, class T, size_t... I, size_t... J>
struct tuple_element_helper<N, T, std::index_sequence<I...>, std::index_sequence<J...>,
void_t<decltype( T{ubiq<I>{}..., exact<std::string>{}, ubiq<J>{}...} )>> {
using type = std::string;
};
} // namespace detail
template <size_t N, class T>
struct tuple_element {
using type = typename detail::tuple_element_helper<N, T>::type;
};
template <size_t N, class T>
using tuple_element_t = typename tuple_element<N, T>::type;
namespace detail {
template <class T, class = std::make_index_sequence<tuple_size<T>::value>>
struct as_tuple_helper;
template <class T, size_t... I>
struct as_tuple_helper<T, std::index_sequence<I...>> {
using type = std::tuple<tuple_element_t<I, T>...>;
};
} // namespace detail
template <class T>
using as_tuple_t = typename detail::as_tuple_helper<T>::type;
} // namespace reflect
struct s {
int a;
size_t b;
int x;
std::string q;
};
int main()
{
std::cout << reflect::tuple_size<s>() << std::endl;
std::cout << typeid( reflect::tuple_element_t<0, s> ).name() << std::endl;
std::cout << typeid( reflect::tuple_element_t<1, s> ).name() << std::endl;
std::cout << typeid( reflect::tuple_element_t<2, s> ).name() << std::endl;
std::cout << typeid( reflect::tuple_element_t<3, s> ).name() << std::endl;
std::cout << typeid( reflect::as_tuple_t<s> ).name() << std::endl;
}
+1
Сейчас на github лежит версия, которая может работать в C++14 с любыми пользовательскими типами данных и не использует их явное перечисление.
Она является чем-то отдалённо похожим на смесь вашего предложения и того что описано в статье: github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/core14_loophole.hpp
Буду рад любым предложениям по улучшению.
Она является чем-то отдалённо похожим на смесь вашего предложения и того что описано в статье: github.com/apolukhin/magic_get/blob/develop/include/boost/pfr/detail/core14_loophole.hpp
Буду рад любым предложениям по улучшению.
+1
Очень интересно, но для реальной практики (вроде той задачи про 1000 структур и 3000 сериализаторов) лично я скорее взял бы внешний кодогенератор, чем пошёл по такому пути.
+1
Снимаю шляпу. Автор этой магии продолжает дело Александреску.
Но согласен с предыдущим комментарием про кодогенерацию сторонними средствами. Боюсь даже представить как тут будет выглядеть ошибка компиляции и чего...
+1
Внешняя кодогенерация требует проверки на то, что внешний кодогенератор отработал на стадии компиляции. И тут «эта магия» вот прямо вот сейчас мне помогает. Я могу хоть как-то проверить, что сборка проходит правильно.
0
Боже мой, неужели это читаемо?
Зачем делать на языке, который чисто академический, то для чего он не предназначен?
В общем-то подобный пост лишь еще одно свидетельство что на С++ писать не надо.
Зачем делать на языке, который чисто академический, то для чего он не предназначен?
В общем-то подобный пост лишь еще одно свидетельство что на С++ писать не надо.
-4
Вы специально открываете статьи по C++, чтобы в очередной раз убедиться в его сложности и сообщить об этом всем окружающим?
+1
а вы бы хотели встретить такое в продакшн коде?..
-1
Sign up to leave a comment.
Рефлексия в C++14