Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.190.152.38] |
|
Страницы: (4) 1 2 [3] 4 все ( Перейти к последнему сообщению ) |
Сообщ.
#31
,
|
|
|
Flex Ferrum, глянь плс бегло эту реализацию макросов. Просто дай оценку. Интересно
|
Сообщ.
#32
,
|
|
|
Ну куда-то в эту сторону, да. Только для нативного C++.
|
Сообщ.
#33
,
|
|
|
Цитата Flex Ferrum @ Только для нативного C++. Да, Haxe - считай метаязык. Потом из него можно C++ код получить, как вариант. |
Сообщ.
#34
,
|
|
|
Сообщ.
#35
,
|
|
|
Сообщ.
#36
,
|
|
|
Итак, первые шаги автопрограммиста по полю метаклассов. Сегодня таки получился end-to-end-тест. Итак.
Объявление метакласса: METACLASS_DECL(Interface) { static void GenerateDecl() { compiler.message("Hello world from metaprogrammer!"); compiler.require($Interface.variables().empty(), "Interface may not contain data members"); for (auto& f : $Interface.functions()) { compiler.require(f.is_public(), "Inteface function must be public"); f.make_pure_virtual(); } } }; Его инстанс: METACLASS_INST(Interface, TestIface) { public: void TestMethod1(); std::string TestMethod2(int param) const; }; Что генерирует автопрограммист в соответствии с определением того и другого: class TestIface { public: virtual void TestMethod1() = 0; virtual std::string TestMethod2(int param) const = 0; protected: private: }; Ну и как это потом используется в коде: class TestIfaceImpl : public TestIface { // TestIface interface public: void TestMethod1() override; std::string TestMethod2(int param) const override; }; void TestIfaceImpl::TestMethod1() { } std::string TestIfaceImpl::TestMethod2(int) const { return "Hello World!"; } Всё настолько прозрачно, насколько это вообще возможно. |
Сообщ.
#37
,
|
|
|
Продолжаем экзерсизы перед выступлением на CoreHard++. Потихоньку привожу в чувство такой вот код:
|
Сообщ.
#38
,
|
|
|
В общем, в итоге оно заработало. Итак, что мы имеем.
1. Два метакласса, описывающие, что именно нужно добавить в класс, чтобы он был сериализуемым с помощью буста: $_metaclass(BoostSerializable) { static void GenerateDecl() { $_inject(public) [&, name="serialize"](const auto& ar, unsigned int ver) -> void { $_constexpr for (auto& v : $BoostSerializable.variables()) $_inject(_) ar & $_v(v.name()); }; } }; $_metaclass(BoostSerializableSplitted) { static void GenerateDecl() { $_inject(public) [&, name="load"](const auto& ar, unsigned int ver) -> void { $_constexpr for (auto& v : $BoostSerializableSplitted.variables()) $_inject(_) ar << $_v(v.name()); }; $_inject(public) [&, name="save"](const auto& ar, unsigned int ver) -> void { $_constexpr for (auto& v : $BoostSerializableSplitted.variables()) $_inject(_) ar >> $_v(v.name()); }; $_inject(public) [&, name="serialize"](auto& ar, const unsigned int ver) -> void { boost::serialization::split_member(ar, $_str(*this), ver); }; } }; Дальше объявляем классы, как обычные структуры. Ну... Почти обычные: $_struct(TestStruct, BoostSerializable) { int a; std::string b; }; $_struct(TestStruct1, BoostSerializableSplitted) { int a; std::string b; }; Метапрограммист делает "вжух" и на выходе получается: class TestStruct { public: template <typename T0> void serialize(const T0 &ar, unsigned int ver) { ar &a; ar &b; ; } int a; std::string b; protected: private: }; class TestStruct1 { public: template <typename T0> void load(const T0 &ar, unsigned int ver) { ar << a; ar << b; ; } template <typename T0> void save(const T0 &ar, unsigned int ver) { ar >> a; ar >> b; ; } template <typename T0> void serialize(T0 &ar, const unsigned int ver) { boost::serialization::split_member(ar, *this, ver); } int a; std::string b; protected: private: }; Добавлено Такое вот средство копипасты. Причём, замечу, там ошибка в объявлении типа параметра ar. Изменяем пару мест в объявлении метаклассов: $_metaclass(BoostSerializable) { static void GenerateDecl() { $_inject(public) [&, name="serialize"](auto& ar, unsigned int ver) -> void { $_constexpr for (auto& v : $BoostSerializable.variables()) $_inject(_) ar & $_v(v.name()); }; } }; $_metaclass(BoostSerializableSplitted) { static void GenerateDecl() { $_inject(public) [&, name="load"](auto& ar, unsigned int ver) -> void { $_constexpr for (auto& v : $BoostSerializableSplitted.variables()) $_inject(_) ar << $_v(v.name()); }; $_inject(public) [&, name="save"](auto& ar, unsigned int ver) -> void { $_constexpr for (auto& v : $BoostSerializableSplitted.variables()) $_inject(_) ar >> $_v(v.name()); }; $_inject(public) [&, name="serialize"](auto& ar, const unsigned int ver) -> void { boost::serialization::split_member(ar, $_str(*this), ver); }; } }; Вжух! class TestStruct { public: template <typename T0> void serialize(T0 &ar, unsigned int ver) { ar &a; ar &b; ; } int a; std::string b; protected: private: }; class TestStruct1 { public: template <typename T0> void load(T0 &ar, unsigned int ver) { ar << a; ar << b; ; } template <typename T0> void save(T0 &ar, unsigned int ver) { ar >> a; ar >> b; ; } template <typename T0> void serialize(T0 &ar, const unsigned int ver) { boost::serialization::split_member(ar, *this, ver); } int a; std::string b; protected: private: }; |
Сообщ.
#39
,
|
|
|
С++ Russia на подходе, тулза развивается. Приросла таким вот функционалом:
1. Делаем метакласс, который генерирует visitor для заданного набора типов: 2. Делаем инстанс этого метакласса. Всё просто: 3. И получаем на выходе хорошенький такой классец-визитор с нужными методами: 4. Теперь мы лёгким движением руки добавляем к инстансу ещё метакласс Interface: 5. И инстанс превращается... Превращается инстанс... В элегантный интерфейсный класс визитора: Вуаля! |
Сообщ.
#40
,
|
|
|
А по иерархиям классов можно ходить? Чтоб получить src...dst в отношении предок...потомок.
Добавлено Хотя... а вдруг один ко многим... |
Сообщ.
#41
,
|
|
|
Цитата Qraizer @ А по иерархиям классов можно ходить? Чтоб получить src...dst в отношении предок...потомок. Можно (в идеале). Текущая реализация этого пока не поддерживает. Добавлено О, да, кстати. Твои мультиметоды в этом стиле реализуются более чем тривиально. |
Сообщ.
#42
,
|
|
|
Ну вот я и попытался. Пока можно лишь частично, генерируя visit-методы. Также к сожалению не получилось разделить объявление и определение visit-метода.
|
Сообщ.
#43
,
|
|
|
Цитата Qraizer @ Пока можно лишь частично, генерируя visit-методы. Угу. А ты прям на автопрограммисте играешься? Добавлено Цитата Qraizer @ Также к сожалению не получилось разделить объявление и определение visit-метода. Будет позже. |
Сообщ.
#44
,
|
|
|
Не. Просто пробую хотя бы представить себе, как бы это выглядело. Нужно генерить объявления
virtual typename Proto::ret_type Accept(typename Proto::template getArg<PList>::type &a); typename Proto::ret_type Concrete::Accept(typename Proto::template getArg<PList>::type &a){ return static_cast<MultiMethods_Visitor::details::Acceptor<Concrete, typename Proto::ret_type>&>(a).Accept(this); } typedef MultiMethods_Visitor::MakeTList</*...*/> PList; Добавлено Для RTTI нужно только последнее. Добавлено Впрочем, имея последнее, первое два, наверное, реально пропустить через итераторы. |
Сообщ.
#45
,
|
|
|
А, понял. Смотри, как это может выглядеть:
template<typename ... Types> inline void Multimethod(meta::ClassInfo dst, const meta::ClassInfo& src) { meta::ClassInfo dispIface; // Add extra 'Visit' methods to dst dependent on specific type from 'Types' for (auto& t : t_$(Types ...)) $_inject_v(dispIface, public) [name="Dispatch", is_pure=true](const $_t(t)* obj) {} $_inject_v(dst, public) dispIface; meta::ClassInfo dispImpl; dispImpl.add_base(dispIface); auto tplParam = dispImpl.add_template_type_param("T"); $_inject_v(dispImpl, private) { const $_t(tplParam)* m_leftObj;} for (auto& t : t_$(Types ...)) { $_inject_v(dispIface, public) [name="Dispatch"](const $_t(t)* obj) {$_str(Call)($_str(m_leftObj), obj);}; $_inject_v(dst) [name="Call"](auto* lhs, auto* rhs) { $_str(lhs)->$_mem("Invoke")(); }; // ... и всё в том же духе } $_inject_v(dst, public) dispImpl; } |