Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 30.04.04 10:29
Оценка: 136 (10)
Всем добрый день. Давно наваял библиотеку для эмуляции рифлексии для С++ обьектов, все времени нет привести это в божеский вид, но прежде всего давно хотелось услышать ваши впечателения и замечания о подходе и решениях.

Перечень предоставляемых сервисов:
1). Создание экземпляра метакласса по строковому названию класса в абстарктной форме, абстрактная фабрика. Возможность создания фабрики для отдельных семейств классов, например для семейства классов оконной системы, и отдельно для семейства прокси классов для удаленных обьектов и так далее. Все это разделение для ускорения регистрации и поиска метаклассов в списках. Далее ведется работа с полученным метаклассом.
2). Получение функтора-конструктора, который умеет создавать экземпляр обьекта. Возможность получения функтора-конструктора по конкретному заданному прототипу.
3). Получение функтора-деструктора, который умеет разрушать ранее созданный экземпляр.
4). Получение функтора-property по строковому имени и типу запрашиваемого свойства.
5). Получение функтора-метода по строковому имени и прототипу запрашиваемого свойства.
6). Инфраструктура сериализации/десериализации обьектов. В перспективе возможность добавить методы клонирования экземпляров на остнове инфраструктуры персистентности.
7). Упрощенные средства регистрации методов, свойств и конструкторов/деструкторов в метаклассах, средства регистрации метаклассов в родовой фабрике.

вот линк на библиотеку:
http://www.rsdn.ru/File/4126/Reflection.rar


Для компиляции использовался VC 7 ( 2003 ), и версия библиотеки Loki годичной давности. Пример использования библиотеки находится в файлах Application.h/cpp, Reflection.cpp.

Как это все выглядит в коде:

    // Смотри файл Reflection.cpp

    //Получение экземпляра метакласса:
    TheClass* pClass = 
            TheClass::GetClass("Application::BusinessLogic::MyClassName");

    //Получение функтора-конструктора по прототипу, заданному в ConstructParamList;
    typedef    TYPELIST_4(    const std_string&, 
                unsigned char, 
                const std_string&,
                unsigned int )                ConstructorParamList;
    typedef    Loki::Functor<    TheObject*, 
                ConstructorParamList >            Constructor;
    
    //В случае отстутствия конструктора с таким прототипом будет выброшено исключение 
    //подобная стратегия применяется для всех запросов к метаклассу
    Constructor    ctor = 
                pClass->GetConstructor<    ConstructorParamList>();

    //Создание экземпляра обьекта с вызовом полученного конструктора
    TheObject* pObj = ctor("Vasya", 27, "London", 12 );
    
    //Get functor to member method
    typedef    Loki::NullType                    VoidParamList;
    typedef    Loki::Functor<void, VoidParamList >            VoidMethod;
    VoidMethod f1 = 
            pClass->GetMethod<void, VoidParamList >(pObj, "f1");
    f1();

    //Get string property
    StringProperty name = pClass->GetProperty<std::string>(pObj, "name");
    name = "Rick";

    //Serialize object
    std::ostrstream    out_stream;
    IO::Formatter::BinaryWriter b_writer(out_stream);
    b_writer << pObj;

    //Удаление экземпляра обьекта
    TheClass::Destructor dtor = pClass->GetDestructor(pObj);
    dtor();


Для определения своего формата сериализации достаточно написать свой Writer&Reader, XMLWriter/XMLReader, IniWriter/IniReader ( реализован только бинарный плоский формат ).
Для сериализации своих типов можно пойти по двум направлениям, либо поле будет использовать рефлексивную сериализацию либо достоточно определить операторы << >> ( как и было проделанно для некоторых STL-ных контейнеров в файле StdStreamOperations.h )

Несколько слов о том как классы адаптируются под инфраструктуру рефлексии:

    //Смотри Application.h/Application.cpp
    using namespace Reflection;
    using namespace    IO::Formatter;

    class    Employee    : 
            public    System::ObjectImpl<    Employee,
                            System::Object<DEFAULT_THREADING> >
    {
    public:
        typedef        std_string                            app_string;
        typedef        Employee                            TheEmployee;
        typedef        System::Object<DEFAULT_THREADING>                TheObject;

    protected:
        app_string            _name;
        byte                _age;
        app_string            _address;
        uint                _department;

        void    DefaultInit();
    public:
        Employee();
        Employee(    
                const app_string&        name, 
                const Reflection::byte&    age,
                const app_string&        address,
                const uint            department );

        virtual    void    PrintEmployee();
        
        DEFINE_STREAMING_OPERATIONS( EmployeeSerializer )
                
        template<
            template< class > class ThreadingModel = DEFAULT_THREADING >
        struct    TheClassImpl    :    
                    public    Reflection::Private::ClassImpl<    TheEmployee ,    
                                        TheObject, 
                                        EmployeeSerializer, 
                                        ThreadingModel >
        {
            TheClassImpl()    
            {
                BindProperty(    "name", 
                        &Employee::_name);
                BindProperty(    "age",
                        &Employee::_age );
                BindProperty(    "address",
                        &Employee::_address );
                BindProperty(    "department",
                        &Employee::_department );
                BindMethod(    "PrintEmployee", 
                        &Employee::PrintEmployee);
                BindConstructor<    
                        const app_string&, 
                        Reflection::byte,
                        const app_string&,
                        uint>(  );
            }
        };

        typedef TheClassImpl<DEFAULT_THREADING>    ClassImpl;
    };


Макро DEFINE_STREAMING_OPERATIONS определяет темплейтную структуру для завязывания операторов << >> в механизм персистенстности, таким образом определив свои операторы в области видимости вашего класса компилятор подхватит эти операторы. Эту структуру можно определить единожды для группы классов, лишь бы операторы сериализации попали в область видимости единицы компиляции.

Позже структуру TheClassImpl можно закрыть макросами, для наглядности был приведен открытый код. Тайпдеф ClassImpl нужен для шаблона System::ObjectImpl, который имплементирует контейнер для экземпляра метакласса. Второй темплейт параметр класса Reflection::Private::ClassImpl определяет семейство для фабрики классов, о которой говорилось ранее, таким образом наш класс находится в семействе классов Object. Конструктор метакласса является регистратором всех полей и методов, которые будут учавствовать в рефлексии и персистентности.

Регистрация метакласса производится макросом в срр файле:
    REGISTER_CLASS( Employee_Class_Tag, Application::BusinessLogic::Employees::Employee)


Шаблонный параметр литерал с внешней компоновкой оказался не так удобен, думаю потом я заменю этот макрос и первый его параметр за ненадобностью отпадет. В библиотеке наверняка куча багов, писал это все полтора года назад, после все ушло в стол и не применялось, так что наверняка есть кривости.

За деталями обращайтесь к коду. Буду рад любым фидбекам



06.07.04 17:33: Перенесено модератором из 'C/C++' по просьбе автора. — Павел Кузнецов
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re: Применения инфраструктуры Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 30.04.04 10:32
Оценка:
Теперь несколько слов о применимости этой инфраструктуры. Ну сама персистентность будет ценна для системы документов, сохранения и востановления настроек приложения в файлах конфигурации разных форматов. Незаменима она в реализации сетевых протоколов. Вот к примеру как можно сериализовать в сеть вызов метода и параметров метода удаленного обьекта, код схематический:

    struct MethodCall : public    System::ObjectImpl<    MethodCall2Params<T1, T2, R>, 
                            System::Object<DEFAULT_THREADING> >
    {
        // идентификатор обьекта, который позволяет получить экземпляр обьекта  в адресном пространстве удаленной машины
        ObjectRuntimeId    _ObjId; 
        std_string        _MethodName;
        
        //Блок для регистрации полей в метаклассе
        //
            BindProperty(    "ObjectId", 
                    &MethodCall::_ObjId );
            BindProperty(    "MethodName", 
                    &MethodCall::_MethodName);
        //
        //Блок для регистрации полей в метаклассе
        
        virtual    void    CallMethod() = 0;
    };

    template< typename T1, typename T2, typename R >
    struct    MethodCall2Params : public    System::ObjectImpl<    MethodCall2Params<T1, T2, R>, 
                                MethodCall >
    {
        typedef    typename        MethodCall2Params<T1, T2, R>    MethodCall2ParamsImpl;
        T1 _Param1;
        T2 _Param2;
        R _RetVal;
        //Блок для регистрации полей в метаклассе
            BindProperty(    "P1", 
                    &MethodCall2ParamsImpl::_Param1 );
            и так далее...
        //Блок для регистрации полей в метаклассе
        void    CallMethod()
        {
            TheObject* pObj = GetObjectFromRepository( _ObjId );
            TheClass* pClass = pObj->GetClass();
            typedef    TYPELIST_2(    T1, 
                        T2 )    PARAM_LIST;
            Loki::Functor<R,PARAM_LIST> pFn = pClass->GetMethod< R, PARAM_LIST>(_MethodName);
            _RetVal = pFn( _Param1, _Param2 );
        }
    };


Макросы регистрации метаклассов и прочее. И так, не вдаваясь в подробности транспорта, на клиентской стороне "сериализуется" вызов метода, на серверной стороне вынимается из стрима абстрактный обьект MethodCall* и делается вызов CallMethod. Дальше в том же стиле нужно отправить результат обратно. Таким образом не чувствуется ограничение нашей строготипизированной рефлексии, методы обьектов вызываются привычным для С++ программистов образом, и сохраняется динамичность.
Многие могут найти применение данного подхода в приемах программирования, основанных на дизайне с другими видами контрактов. Время будет тратиться только на получение функторов методов, далее же вызов будет эквивалентен виртуальному вызову, так что в итеративных вызовах полученного ранее прокси на метод разница не чувствуется, можно и вовсе отказаться от базовых классов и перекрытия виртуальных методов, столь привычных С++ программистам, появляется возможность имитировать стиль программирования принятый на Смолтоке, что наложит отпечатки на дизайн и приемы проектирования, при этом нет необходимости заполнять страшные стеки параметров динамических Invoke, свойственные рефлексиям джавоидов.

Еще одна тема, которую мне бы хотелось обсудить, это возможность сохранения дополнительных метаинструкций для рефлексивных полей класса, которые в последствии могут применяться для генерации и разметки визуального интерфейса, представляющего содержимое данного класса. Инными словами дизайн паттерн МВЦ по большому счету большой и бесконечный workaround, хотелось бы писать компоненту и сопровождать ее кодом разметки, по которому конкретный фреймворк мог генерить как миниму визуализацию компоненты и фронтсайт контроллер, компонента же будет выступать в роли бексайт контроллера. Таким образом, WEB framework генерит веб визуализацию компоненты, GUI framework генерит окна и так далее. Хотелось бы обсудить этот вопрос, попытаться формализовать эту идею.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re: Reflection для С++ классов
От: Tom Россия http://www.RSDN.ru
Дата: 30.04.04 13:09
Оценка: +1 -8
B> За деталями обращайтесь к коду. Буду рад любым фидбекам

Ну зачем писать на плюсах, то, для чего он не преднозначен.
Давайте ещё XML серилизацию прикрутим к ASM-му.
Ну не для этого создан С++. Для этого есть ява и шарп.
... << RSDN@Home 1.1.0 stable >>
Народная мудрось
всем все никому ничего(с).
Re[2]: Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 30.04.04 14:40
Оценка:
Здравствуйте, Tom, Вы писали:

B>> За деталями обращайтесь к коду. Буду рад любым фидбекам


Tom>Ну зачем писать на плюсах, то, для чего он не преднозначен.

Tom>Давайте ещё XML серилизацию прикрутим к ASM-му.
Tom>Ну не для этого создан С++. Для этого есть ява и шарп.

Честно сказать под любыми фидбеками подразумевались отзывы по существу, просто не хочется заводить флейм о крутизне языков

Том, если вы заметели то речь идет не только о сериализации, это лишь один аспект рефлексии. Что касатеся назначения С++, то язык этот обладает хорошими средствами для манипуляций с данными ( может и не максимально элегантными, в свете последних пересмотров парадигм программирования ), адаптации одного вида данных к другому виду, в том числе и визуальное представление данных. Хотя я категорически против того что бы программеры вообще строили код визуализации данных, и уж тем более не на С++, но тем не менее более 60% программеров занимаются именно этим, и не малая часть из них предпочитает решать эти задачи как не странно именно на С++, особенно после того как мода на ВБ и Дельфи прошла, а старые проблемы остались по прежнему не решенными. К сожалению шарп и джава так же не в состоянии решить многие проблемы, связанные с пересмотром парадигм программирования, подходов к манипуляции и преобразованию данных из разных форм с минимальными затратами кода, о которых я хотел было поговорить на форуме.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[2]: Применения инфраструктуры Reflection для С++ классов
От: Аноним  
Дата: 30.04.04 21:45
Оценка:
Здравствуйте, Batiskaf, Вы писали:

B> ...

B> Инными словами дизайн паттерн МВЦ по большому счету большой и бесконечный workaround,
B> ...
ИМХО минимум спорное утверждение.

Относительно рефлексии: мне кажется наиболее ценная чась всей этой кухни — это маршалинг/демаршалинг объектов, навороты вроде вызова методов по именам — лишнее. Вот если твоя штука позволит достаточно просто и аккурутно приделать возможность серриализации классов — это классно. Вот так к примеру:
несерриализуемый класс:
class A
{
    int a;
    std::string b;
};

серриализуемый класс:
template <class T> class Serializer;
class A
{
    int a;
    std::string b;

    friend class Serializer<A>;
};

В идеале специализация Serializer<A> должна генерится автоматически какой-нибудь тулзой, которая будет парсить обявление класса A. Но это наверное слишком жирно , я б даже согласился на то, чтобы сделать это руками.
Еще один момент: то что у тебя сейчас код вроде
BindProperty("name", &Employee::_name);

висит в объявлении класса — мерзко, было бы здорого если бы этот background можно было из класса убрать
Re: Reflection для С++ классов
От: c-smile Канада http://terrainformatica.com
Дата: 30.04.04 23:42
Оценка: 16 (1)
Здравствуйте, Batiskaf, Вы писали:

Клево!

И немного в сторону... У К.Книжника есть тоже reflection package for C++
У него метаинформарция генерируется автоматически — достается из debug information.
Re[3]: Применения инфраструктуры Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 01.05.04 06:17
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Batiskaf, Вы писали:


B>> ...

B>> Инными словами дизайн паттерн МВЦ по большому счету большой и бесконечный workaround,
B>> ...
А>ИМХО минимум спорное утверждение.
Ок, так давайте же спорить! Очень рад выслушать вашу мотивацию того, что код адаптации данных к визуальному интерфейсу не является монотонной рутиной, которую не возможно в большинстве случаев автоматизировать.

А>Относительно рефлексии: мне кажется наиболее ценная часть всей этой кухни — это маршалинг/демаршалинг объектов, навороты вроде вызова методов по именам — лишнее. Вот если твоя штука позволит достаточно просто и аккурутно приделать возможность серриализации классов — это классно.

Ок, я привел примеры использования вызовов с поздним связыванием касательно сетевых решений, которые значительно упростят жизнь. Этим дело не ограничивается, представьте себе конфигурационные файлы, в которых помимо данных будут вписываться имена методов для запуска некоторых операций. Ваше дело пользоваться этим всем или нет.

А>я б даже согласился на то, чтобы сделать это руками.

У меня именно руками это и делается, нужно проделать разметку класса, одноразово зарегистрировать поля, дальше все получается бесплатно.

А>Еще один момент: то что у тебя сейчас код вроде

А>
А>BindProperty("name", &Employee::_name);
А>

А>висит в объявлении класса — мерзко, было бы здорого если бы этот background можно было из класса убрать
Мне казалось что наоборот гораздо проще и нагляднее рядом с обьявлением полей класса видеть код заполнения метакласса, в случае если вы что то меняете в обьявлении, тут же правится метакласс. В последствии я планировал в коде регистрации поля дать возможность добавлять метаинструкции произвольной формы для данного поля, как я уже говорил, для того что бы давать более развернутую информацию о классе и его полях, возможность генерировать код к примеру визуализации обьекта этого класса, или код манипуляции с этим обьектом, речь идет об экзотических автоматизированных контрактах, которые могут упростить жизнь программиста.

В любом случае здорово, завязалось обсуждение, большое мерси
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[2]: Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 01.05.04 06:21
Оценка: +1
Здравствуйте, c-smile, Вы писали:

CS>Здравствуйте, Batiskaf, Вы писали:


CS>Клево!


CS>И немного в сторону... У К.Книжника есть тоже reflection package for C++

CS>У него метаинформарция генерируется автоматически — достается из debug information.

Большое спасибо за информацию, но на сколько я понимаю его метод подходит лишь для не многого набора компиляторов, debug information не стандартизирован и от компилятора к компилятору имеет разные форматы.

Спасибо за участие в обсуждении
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[3]: Reflection для С++ классов
От: c-smile Канада http://terrainformatica.com
Дата: 01.05.04 06:42
Оценка:
Здравствуйте, Batiskaf, Вы писали:

B>Большое спасибо за информацию, но на сколько я понимаю его метод подходит лишь для не многого набора компиляторов, debug information не стандартизирован и от компилятора к компилятору имеет разные форматы.


В принципе да. Но когда тебе надо поднять классов эдак 100,
то тут уж не до жиру — и GCC установится как миленький.

Хотя это конечно какой-то мрачный дизайн — 100 сериализуемых классов.
Re[4]: Применения инфраструктуры Reflection для С++ классов
От: Аноним  
Дата: 01.05.04 10:04
Оценка:
Здравствуйте, Batiskaf, Вы писали:

B>Здравствуйте, Аноним, Вы писали:


А>>Здравствуйте, Batiskaf, Вы писали:


B>>> ...

B>>> Инными словами дизайн паттерн МВЦ по большому счету большой и бесконечный workaround,
B>>> ...
А>>ИМХО минимум спорное утверждение.
B>Ок, так давайте же спорить! Очень рад выслушать вашу мотивацию того, что код адаптации данных к визуальному интерфейсу не является монотонной рутиной, которую не возможно в большинстве случаев автоматизировать.
То что данные и визуальный интерфейс должны быть отдельно — это вроде очевидно. ИМХО полезна не автоматическая генерация UI из данных, а автоматизированная . Я не спорю, что автоматизировать нельзя — можно и нужно, но гибкость должна быть.

А>>Еще один момент: то что у тебя сейчас код вроде

А>>
А>>BindProperty("name", &Employee::_name);
А>>

А>>висит в объявлении класса — мерзко, было бы здорого если бы этот background можно было из класса убрать
B>Мне казалось что наоборот гораздо проще и нагляднее рядом с обьявлением полей класса видеть код заполнения метакласса, в случае если вы что то меняете в обьявлении, тут же правится метакласс. В последствии я планировал в коде регистрации поля дать возможность добавлять метаинструкции произвольной формы для данного поля, как я уже говорил, для того что бы давать более развернутую информацию о классе и его полях, возможность генерировать код к примеру визуализации обьекта этого класса, или код манипуляции с этим обьектом, речь идет об экзотических автоматизированных контрактах, которые могут упростить жизнь программиста.
Затея слишком амбициозная — генерить GUI автоматически. Вот пример: есть писок контактов в телефонной книге, контакт описан так:
class Person
{
    std::string name;
    std::string secondName;
    std::string nick;
    int         homePhone;
    int         mobilePhone;
    std::string email;
    int         imNumber;
    int         icqNumber;
    Image       smallPhoto;
    Image       bigPhoto;
};

Телефонная книга — приложение в мобильнике. Теперь представь сколькими способами можно визуализовать класс Person. Вот пара примеров: когда на трубку звонит человек надо показать телефон с корого он звонит и smallPhoto; когда юзверь хочет кому-то позвонить, он будет листать список из контактов, при этом показывать ему всякую лабуду, кроме номеров телефонов смысла нет, аналогично, если хочет email отправить, то телефоны показывать не надо.
Я другого сопсоба кроме как руками все сделать не вижу, а вот серриализовать std::vector<Person> можно и автоматически.
Для экзотики вроде удаленных вызовов есть CORBA, тут ловить с рефлекшеном нечего. Вообщем ИМХО не надо пытаться всех осчастливить.
Re[5]: Применения инфраструктуры Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 01.05.04 11:45
Оценка:
Здравствуйте, Аноним, Вы писали:

А>>>висит в объявлении класса — мерзко, было бы здорого если бы этот background можно было из класса убрать

B>>Мне казалось что наоборот гораздо проще и нагляднее рядом с обьявлением полей класса видеть код заполнения метакласса, в случае если вы что то меняете в обьявлении, тут же правится метакласс. В последствии я планировал в коде регистрации поля дать возможность добавлять метаинструкции произвольной формы для данного поля, как я уже говорил, для того что бы давать более развернутую информацию о классе и его полях, возможность генерировать код к примеру визуализации обьекта этого класса, или код манипуляции с этим обьектом, речь идет об экзотических автоматизированных контрактах, которые могут упростить жизнь программиста.
А>Затея слишком амбициозная — генерить GUI автоматически. Вот пример: есть писок контактов в телефонной книге, контакт описан так:
А>
А>class Person
А>{
А>    std::string name;
А>    std::string secondName;
А>    std::string nick;
А>    int         homePhone;
А>    int         mobilePhone;
А>    std::string email;
А>    int         imNumber;
А>    int         icqNumber;
А>    Image       smallPhoto;
А>    Image       bigPhoto;
А>};
А>

А>Телефонная книга — приложение в мобильнике. Теперь представь сколькими способами можно визуализовать класс Person. Вот пара примеров: когда на трубку звонит человек надо показать телефон с корого он звонит и smallPhoto; когда юзверь хочет кому-то позвонить, он будет листать список из контактов, при этом показывать ему всякую лабуду, кроме номеров телефонов смысла нет, аналогично, если хочет email отправить, то телефоны показывать не надо.
А>Я другого сопсоба кроме как руками все сделать не вижу, а вот серриализовать std::vector<Person> можно и автоматически.
Ок, отличный пример. Значит рассмотрим этот пример с несколькими видами козалось бы одной и той же информации. Для начала второй случай относится к генерации вида всей коллекции контактов по заданным условиям, два других случая относятся к генерации вью для отдельного элемента этой книги, ситуации совершенно разные, так что рассмотрим все по отдельности.

Генерация видов для конкретной записи в book: в данном случае речь идет о разных видах адаптации структуры Person для разных ситуаций. Я сведу это к двум типовым ситуациям, один раз структура Person конвертируется привычным для программера C++ образом в структуру PersonOnCall:


struct PersonOnCall
{
    PersonOnCall( const Person& person ){...}
    std::string     _name;
    Image          _Photo;
};

Структура сопровождается метаинструкциями, по которым должен генериться диалог, я еще не формализовал эти инструкции, только идея, но смысл в том что бы снабдить поля информацией для генераторов, например если в структуре есть поле int (псевдо код):


struct MyStruct
{
    [UpDown(0,100)]
    int a;
};


то я указываю что это поле нужно отобразить как поле с движком с определенными границами. В случае с PersonOnCall поле имени наверное не стоит сопровождать метакодом, дифолтивно это будет поле без возможности ввода, только на чтение, int кстати дифолтивно логично отображать таким же макаром. В случае с Image, это будет наверняка пользовательский тип с поддержкой рефлексии, с метеинструкциями как генерить для него свой вид. Таким образом написание диалога будет сводиться к определению структуры с метаинструкциями, и задействование конструктора-кастинга, программер остается в рамках преобразования типов данных, как и должно тому быть, ну и максимум инструктирование генераторов, что нужно проделать с обьектом что бы корректно его отобразить. Во втором случае нужно строить структуру MailPerson, и так далее и тому подобное.


А>Для экзотики вроде удаленных вызовов есть CORBA, тут ловить с рефлекшеном нечего. Вообщем ИМХО не надо пытаться всех осчастливить.

А для GUI есть МФЦ, и главное все довольны
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[6]: Применения инфраструктуры Reflection для С++ классов
От: Аноним  
Дата: 01.05.04 17:59
Оценка:
Здравствуйте, Batiskaf, Вы писали:

...

B>Генерация видов для конкретной записи в book: в данном случае речь идет о разных видах адаптации структуры Person для разных ситуаций. Я сведу это к двум типовым ситуациям, один раз структура Person конвертируется привычным для программера C++ образом в структуру PersonOnCall:

Привычным образом это как? Руками?

Еще, я так понимаю, в PersonOnCall надо будет втянуть все необходимые BindProperty. Ну ладно пусть так. Но элегантности уже стало поменьше

B>
B>struct PersonOnCall
B>{
B>    PersonOnCall( const Person& person ){...}
B>    std::string     _name;
B>    Image          _Photo;
B>};
B>

B>Структура сопровождается метаинструкциями, по которым должен генериться диалог, я еще не формализовал эти инструкции, только идея, но смысл в том что бы снабдить поля информацией для генераторов, например если в структуре есть поле int (псевдо код):


B>
B>struct MyStruct
B>{
B>    [UpDown(0,100)]
B>    int a;
B>};
B>

Вот тут и начнется мрак: дальше потребуется поддерживать маски для ввода текстовой информации (regexp-ы), например для ввода email-ов, потом еще какую-нибудь блаж.
Это все конечно решается, но при этом твоя замечательная библиотека будет постепенно превращаться в монстра
Не лепи все в кучу. Пусть отдельно будет рефлексия — основа твоей библиотеки, не надо туда метаинструкции для генерации GUI лепить, оставь только серриализацию. А для генерации GUI сделай отдельную библиотеку.
Re: Reflection для С++ классов
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 01.05.04 19:19
Оценка:
Batiskaf wrote:

> Всем добрый день. Давно наваял библиотеку для эмуляции рифлексии для С++

> обьектов, все времени нет привести это в божеский вид, но прежде всего
> давно хотелось услышать ваши впечателения и замечания о подходе и
> решениях.
Тебе пора в boost.langbinding. Жалко там сейчас тишина
--
Александр Насонов,
Независимый консультант и разработчик ПО
Posted via RSDN NNTP Server 1.8
Re[7]: Применения инфраструктуры Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 01.05.04 19:31
Оценка:
А>

А>Привычным образом это как? Руками?

А>Еще, я так понимаю, в PersonOnCall надо будет втянуть все необходимые BindProperty. Ну ладно пусть так. Но элегантности уже стало поменьше

Дык все делается руками, только если сравнить количество траха, то я предпочту написать и сопроводить метакодом логичную и простую структуру нежели возиться с OnInitDialog, листенерами и сервлетами, и все это ради того что бы показать этого несчастного персона на экране Программисту гораздо проще заниматься адаптациями одних структур под другие, большую часть времени мы все этим и занимаемся, масса гибких идеом, а вот с графической адаптацией все по прежнему в каменном веке.

B>>
B>>struct PersonOnCall
B>>{
B>>    PersonOnCall( const Person& person ){...}
B>>    std::string     _name;
B>>    Image          _Photo;
B>>};
B>>

B>>Структура сопровождается метаинструкциями, по которым должен генериться диалог, я еще не формализовал эти инструкции, только идея, но смысл в том что бы снабдить поля информацией для генераторов, например если в структуре есть поле int (псевдо код):


B>>
B>>struct MyStruct
B>>{
B>>    [UpDown(0,100)]
B>>    int a;
B>>};
B>>

А>Вот тут и начнется мрак: дальше потребуется поддерживать маски для ввода текстовой информации (regexp-ы), например для ввода email-ов, потом еще какую-нибудь блаж.
А>Это все конечно решается, но при этом твоя замечательная библиотека будет постепенно превращаться в монстра
Можно предусмотреть дифолтивные параметры для конструктора UpDown метаинструкции, значение инициализации, другие конструктора, в конце концов определить другой метатаг, который будет определять новый элемент, система должна быть расширяемой, естественно.

А>Не лепи все в кучу. Пусть отдельно будет рефлексия — основа твоей библиотеки, не надо туда метаинструкции для генерации GUI лепить, оставь только серриализацию. А для генерации GUI сделай отдельную библиотеку.


Я хочу определить свою позицию, генерацию визуального интерфейса я рассматриваю как частный случай сериализации, так понятнее будет? По-большому счету любое преобразование данных из одной формы в другую можно рассматривать как сериализацию данных в другой формат, можно сериализоваться в XML, можно HTML, а можно и... в MFC. И главное определив этот механизм единожды, можно получить огромный выигрыш в стоимости разработки и сопровождении таких приложений.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[2]: Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 01.05.04 19:36
Оценка:
Здравствуйте, alnsn, Вы писали:

A>Batiskaf wrote:


>> Всем добрый день. Давно наваял библиотеку для эмуляции рифлексии для С++

>> обьектов, все времени нет привести это в божеский вид, но прежде всего
>> давно хотелось услышать ваши впечателения и замечания о подходе и
>> решениях.
A>Тебе пора в boost.langbinding. Жалко там сейчас тишина
A>--
A>Александр Насонов,
A>Независимый консультант и разработчик ПО

Если бы кто просвятил что это такое boost.langbinding, то я бы с радостью
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[3]: Reflection для С++ классов
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 01.05.04 20:09
Оценка:
Batiskaf wrote:

> Если бы кто просвятил что это такое boost.langbinding, то я бы с радостью

>
Не ожидал такого быстрого ответа. Все эрэсдеэнщики должны под столом пьяные
лежать

Если есть news client, то здесь
news://news.gmane.org/gmane.comp.lib.boost.langbinding

или подписаться здесь (а заодно и посмотреть)
http://sourceforge.net/mail/?group_id=7586

--
Александр Насонов,
Независимый консультант и разработчик ПО
Posted via RSDN NNTP Server 1.8
Re[4]: Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 01.05.04 20:24
Оценка:
Здравствуйте, alnsn, Вы писали:

A>Batiskaf wrote:


>> Если бы кто просвятил что это такое boost.langbinding, то я бы с радостью

>>
A>Не ожидал такого быстрого ответа. Все эрэсдеэнщики должны под столом пьяные
A>лежать

A>Если есть news client, то здесь

A>news://news.gmane.org/gmane.comp.lib.boost.langbinding

A>или подписаться здесь (а заодно и посмотреть)

A>http://sourceforge.net/mail/?group_id=7586

A>--

A>Александр Насонов,
A>Независимый консультант и разработчик ПО

( голос из-под стола ) — бальшое мерси за линки Не стесняйтесь, присоединяйтесь к обсуждению
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re[5]: Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 04.05.04 07:46
Оценка:
В надежде продолжить обсуждение о темах, затронутым в топике.

Речь идет о имплементации метаинструкций, хотелось бы услышать ваши идеи, как гибко и негромоздко приатачить эту фишку к уже имеющейся инфре. Для начала сформулирую мотивацию и требования.

Имплементация паттерна Persistence на основе рефлексии дает много преимуществ в области унифицированного преобразования моделей данных из одного вида в другой, представление модели данных в разных контрактах (хмл файл интерпретирует struct Person в одном контракте, диалог отображения struct Person интерпретирует эту же модель в другом контракте). Но одной информации о типе элемента модели не достаточно для более точной интерпретации модели в другой контракт, нужно дополнительно проинструктировать интерпретатор модели о возможных вариантах. Инструкции нужно уметь разбирать динамически на равне с динамическим разбором элементов модели, инструкция должна знать к какому контракту интерпретации она относится, что бы вносить одновременно по нескольку инструкций на тот же элемент модели для разных конрактов (допустим что модель можно интерпретировать сразу в несколько разных контрактов). На момент интерпретации инструкции относящиеся к другому типу конракта будут игнорироваться.

Можно так же рассмотреть метаинструкцию как дополнительный модификатор. Идея в следующем, для преобразования модели данных в другую модель в рамках одного контракта (апроксимация, всевозможные методы модификации модели данных), мы используем традиционные функциональные средства программинга. Возможно ли применить метаинструкцию элемента модели как модификатор, учавствующий в процессе трансформации модели? Может я запутанно обьясняюсь, удобно ли было применять эту инфраструктуру уже не как персистенс, а как обобщенную инфраструктуру преобразование структур данных, к примеру из одной системы в другую (например из классов определенных в namespace MyApplication::A в классы определенные в namespace YourApplication::BlaBla), посредством настраивания модификаторов и их запуска в процессе преобразования. Может эта идея еще очень туманная, но было бы интересно выслушать и ваши идеи, просто мнения, какие интересные виды взаимодействия структур данных вы хотели бы закодировать.

Может у кого то есть уже несколько слов касательно реализации моей библиотеки?
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Re: Reflection для С++ классов
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 04.05.04 08:04
Оценка: -1
Здравствуйте, Batiskaf, Вы писали:

Возможно я не все понимаю, можно просто уточнить некоторые вопросы? Честно признаюсь, исходники не смотрел, и возможно, что многие мои вопросы просто глупые.

B>...


B>Перечень предоставляемых сервисов:

B>1). Создание экземпляра метакласса по строковому названию класса в абстарктной форме, абстрактная фабрика. ...
Почему именно строковый? А можно какой нибудь run-time generated id? Например int? А строки уже можно ставить в соответствие этому id.

B>2). Получение функтора-конструктора, который умеет создавать экземпляр обьекта. Возможность получения функтора-конструктора по конкретному заданному прототипу.

Это клонирование?

B>4). Получение функтора-property по строковому имени и типу запрашиваемого свойства.

B>5). Получение функтора-метода по строковому имени и прототипу запрашиваемого свойства.
Тот же вопрос что и в первом случае.

B>Для компиляции использовался VC 7 ( 2003 ), и версия библиотеки Loki годичной давности.

Может лучше попробовать boost привязать вместо Loki? Глядишь, больше народу заинетересуеться с точки зрения использования.
getboost.codeplex.com
citylizard.codeplex.com
Re[2]: Reflection для С++ классов
От: Batiskaf Израиль http://www.mult.ru/
Дата: 04.05.04 09:45
Оценка:
Здравствуйте, sergey_shandar, Вы писали:

_>Возможно я не все понимаю, можно просто уточнить некоторые вопросы? Честно признаюсь, исходники не смотрел, и возможно, что многие мои вопросы просто глупые.

Ок, глупых вопросов не бывает, бывает не достаточно понятные обьяснения, наверняка как в моем случае.

B>>1). Создание экземпляра метакласса по строковому названию класса в абстарктной форме, абстрактная фабрика. ...

_>Почему именно строковый? А можно какой нибудь run-time generated id? Например int? А строки уже можно ставить в соответствие этому id.

Мне кажется что строковая идентификация это гарантирует достаточную уникальность, если ты взглянишь на макрос регистрации класса ( я его изменю, первый параметр за ненадобностью отпадет), то он принимает путь к классу, и он же используется в качестве строки для регистрации, ошибиться будет сложно, продублировать да, но дать разным классам один путь — нет.

B>>2). Получение функтора-конструктора, который умеет создавать экземпляр обьекта. Возможность получения функтора-конструктора по конкретному заданному прототипу.

_>Это клонирование?
Нет, это имитация вызова конкретного конструктора. Многие реализации абстрактных фабрик основаны на дифолтивном конструкторе, я же даю возможность попытаться построить обьект с вызовом конструктора конкретного прототипа:


//Получение функтора-конструктора по прототипу, заданному в ConstructParamList;
    typedef    TYPELIST_4(    const std_string&, 
                unsigned char, 
                const std_string&,
                unsigned int )                ConstructorParamList;
    typedef    Loki::Functor<    TheObject*, 
                ConstructorParamList >            Constructor;
    
    //В случае отстутствия конструктора с таким прототипом будет выброшено исключение 
    //подобная стратегия применяется для всех запросов к метаклассу
    Constructor    ctor = 
                pClass->GetConstructor<    ConstructorParamList>();

    //Создание экземпляра обьекта с вызовом полученного конструктора
    TheObject* pObj = ctor("Vasya", 27, "London", 12 );


вызов функционала ctor эквивалентно конструированию обьекта pObj посредством вызова конструктора с четырьмя параметрами:

MyTypeName(const std_string&, unsigned char, const std_string&, unsigned int );

Собственно этот конструктор с коректной версией operator new и вызовется, но только в абстрактной форме, это может использоваться в какой то библиотеке на уровне соглашения, все классы библиотеки обязаны имплементировать конкретный конструктор и его регестрировать, для упрощенной инициализации экземпляров.


B>>4). Получение функтора-property по строковому имени и типу запрашиваемого свойства.

B>>5). Получение функтора-метода по строковому имени и прототипу запрашиваемого свойства.
_>Тот же вопрос что и в первом случае.
Как и в первом случае... Есть возможность у конкретного экземпляра при помощи его метакласса получить функциональный обьект, который запускает над этим экземпляром его же метод, или меняет значение поля, напоминает Джаву, только более типизированное.

B>>Для компиляции использовался VC 7 ( 2003 ), и версия библиотеки Loki годичной давности.

_>Может лучше попробовать boost привязать вместо Loki? Глядишь, больше народу заинетересуеться с точки зрения использования.
Не имеет огромного значения, главное что бы была заинтересованность людей, возможно из этой инфры можно выростить что то еще, что нибудь побочное, кое что я уже предложил в этой теме, идей масса, очень рад буду найти одномышленников.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.