На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
Страницы: (4) 1 2 [3] 4  все  ( Перейти к последнему сообщению )  
> Метаклассы в C++ , Мечта или реальность?
    Flex Ferrum, глянь плс бегло эту реализацию макросов. Просто дай оценку. Интересно :)
      Ну куда-то в эту сторону, да. Только для нативного C++.
        Цитата Flex Ferrum @
        Только для нативного C++.

        Да, Haxe - считай метаязык. Потом из него можно C++ код получить, как вариант.
          Цитата Flex Ferrum @
          в Qt я про такое не слышал.

          Как-то так, но в подробности я не вдавался.
            Цитата korvin @
            Цитата Flex Ferrum @
            в Qt я про такое не слышал.

            Как-то так, но в подробности я не вдавался.

            Не, это совсем другое. В Qt moc экспозит метаинформацию в райнтайм. Метаклассы же, о которых здесь идёт речь, работают с метаинформацией в compile-time. И могут модифицировать AST.
              Итак, первые шаги автопрограммиста по полю метаклассов. Сегодня таки получился end-to-end-тест. Итак.
              Объявление метакласса:
              ExpandedWrap disabled
                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();
                        }
                    }
                };

              Его инстанс:
              ExpandedWrap disabled
                METACLASS_INST(Interface, TestIface)
                {
                public:
                    void TestMethod1();
                    std::string TestMethod2(int param) const;
                };

              Что генерирует автопрограммист в соответствии с определением того и другого:
              ExpandedWrap disabled
                class TestIface {
                public:
                  virtual void TestMethod1() = 0;
                  virtual std::string TestMethod2(int param) const = 0;
                 
                protected:
                private:
                };

              Ну и как это потом используется в коде:
              ExpandedWrap disabled
                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!";
                }

              Всё настолько прозрачно, насколько это вообще возможно.
                Продолжаем экзерсизы перед выступлением на CoreHard++. Потихоньку привожу в чувство такой вот код:
                user posted image
                  В общем, в итоге оно заработало. Итак, что мы имеем.

                  1. Два метакласса, описывающие, что именно нужно добавить в класс, чтобы он был сериализуемым с помощью буста:
                  ExpandedWrap disabled
                    $_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);
                            };
                        }
                    };


                  Дальше объявляем классы, как обычные структуры. Ну... Почти обычные:
                  ExpandedWrap disabled
                    $_struct(TestStruct, BoostSerializable)
                    {
                        int a;
                        std::string b;
                    };
                     
                    $_struct(TestStruct1, BoostSerializableSplitted)
                    {
                        int a;
                        std::string b;
                    };


                  Метапрограммист делает "вжух" и на выходе получается:
                  ExpandedWrap disabled
                    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. Изменяем пару мест в объявлении метаклассов:
                  ExpandedWrap disabled
                    $_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);
                            };
                        }
                    };


                  Вжух!
                  ExpandedWrap disabled
                    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:
                    };
                    С++ Russia на подходе, тулза развивается. Приросла таким вот функционалом:

                    1. Делаем метакласс, который генерирует visitor для заданного набора типов:
                    user posted image

                    2. Делаем инстанс этого метакласса. Всё просто:
                    user posted image

                    3. И получаем на выходе хорошенький такой классец-визитор с нужными методами:
                    user posted image

                    4. Теперь мы лёгким движением руки добавляем к инстансу ещё метакласс Interface:
                    user posted image

                    5. И инстанс превращается... Превращается инстанс... В элегантный интерфейсный класс визитора:
                    user posted image

                    Вуаля!
                      А по иерархиям классов можно ходить? Чтоб получить src...dst в отношении предок...потомок.

                      Добавлено
                      Хотя... а вдруг один ко многим...
                        Цитата Qraizer @
                        А по иерархиям классов можно ходить? Чтоб получить src...dst в отношении предок...потомок.

                        Можно (в идеале). Текущая реализация этого пока не поддерживает.

                        Добавлено
                        О, да, кстати. Твои мультиметоды в этом стиле реализуются более чем тривиально. :)
                          Ну вот я и попытался. Пока можно лишь частично, генерируя visit-методы. Также к сожалению не получилось разделить объявление и определение visit-метода.
                            Цитата Qraizer @
                            Пока можно лишь частично, генерируя visit-методы.

                            Угу. А ты прям на автопрограммисте играешься?

                            Добавлено
                            Цитата Qraizer @
                            Также к сожалению не получилось разделить объявление и определение visit-метода.

                            Будет позже.
                              Не. Просто пробую хотя бы представить себе, как бы это выглядело. Нужно генерить объявления
                              ExpandedWrap disabled
                                virtual typename Proto::ret_type Accept(typename Proto::template getArg<PList>::type &a);
                              в нужных классах, определения
                              ExpandedWrap disabled
                                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); }
                              и списки
                              ExpandedWrap disabled
                                typedef MultiMethods_Visitor::MakeTList</*...*/> PList;
                              в нужных местах единиц трансляции. Пока не вижу явных возможностей для реализации.

                              Добавлено
                              Для RTTI нужно только последнее.

                              Добавлено
                              Впрочем, имея последнее, первое два, наверное, реально пропустить через итераторы.
                              Сообщение отредактировано: Qraizer -
                                А, понял. Смотри, как это может выглядеть:

                                ExpandedWrap disabled
                                  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;
                                  }
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (4) 1 2 [3] 4  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0645 ]   [ 17 queries used ]   [ Generated: 29.03.24, 08:51 GMT ]