Использование метаданных в программах на языке C++
От: Аноним Владислав Юдин  
Дата: 23.05.05 11:06
Оценка: 315 (7) +1
Статья:
Использование метаданных в программах на языке C++
Автор(ы): Владислав Юдин
Дата: 22.05.2005
Цель данной статьи — показать, что метаданные это мощный механизм, требующий выделения в отдельный компонент, который хотелось бы видеть в стандартной библиотеке С++.


Авторы:
Владислав Юдин

Аннотация:
Цель данной статьи — показать, что метаданные это мощный механизм, требующий выделения в отдельный компонент, который хотелось бы видеть в стандартной библиотеке С++.

01.09.05 19:00: Перенесено модератором из 'C/C++. Прикладные вопросы' — Павел Кузнецов
Re: Использование метаданных в программах на языке C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 01.09.05 14:30
Оценка: 1 (1) +4
Здравствуйте, Владислав Юдин, Вы писали:

ВЮ>Статья:

ВЮ>Использование метаданных в программах на языке C++
Автор(ы): Владислав Юдин
Дата: 22.05.2005
Цель данной статьи — показать, что метаданные это мощный механизм, требующий выделения в отдельный компонент, который хотелось бы видеть в стандартной библиотеке С++.


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

Сама статья, имхо, очень тяжело читается. В основном, это сплошной навороченный шаблонный код, местами разбавленный односложными фразами, слабо проясняющими назначение кода и его смысл. Имхо, это больше похоже на результат прохода doxygen-а по самописной библиотеке, чем на попытку объяснить полезность метаинформации на шаблонах C++.

ВЮ>Аннотация:

ВЮ>Цель данной статьи — показать, что метаданные это мощный механизм, требующий выделения в отдельный компонент, который хотелось бы видеть в стандартной библиотеке С++.

Имхо, удалось показать, что метаданные на шаблонах это слишком мощный (я бы даже сказал overkill) механизм. Что-то на нем очень круто как-то делается. Только вот что делается, почему это делается именно так, и стоило ли это делать именно так -- для меня остается загадкой. Вот серьезно, я не понял, почему на примере сериализации структур делается вывод о полезности метаинформации. Лично у меня приведенный код не вызывает желания им пользоваться, даже в виде вот такого макросного описания:
META(SPoint, 2)
  ATTR_TYPES AVersion ATTR_VALUES 3 ATTR_END
  META_ENTRY(0)
    ATTR_TYPES AName, AXMLAttribute ATTR_VALUES "x", true ATTR_END
    META_ENTRY_INFO(int, x)
  META_ENTRY(1)
    ATTR_TYPES AName ATTR_VALUES "y" ATTR_END
    META_ENTRY_INFO(int, y)
META_END


Поэтому, если задачей было показать необходимость подобного механизма в стандартной библиотеке C++, то, имхо, эта задача достигнута не была. Чесно говоря я вообще не понял, что за компонент должен быть в стандарной библиотеке и что этот компонент должен делать.

... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Использование метаданных в программах на языке C++
От: Аноним  
Дата: 03.09.05 10:38
Оценка:
Здравствуйте, eao197

ВЮ>>Статья:

ВЮ>>Использование метаданных в программах на языке C++
Автор(ы): Владислав Юдин
Дата: 22.05.2005
Цель данной статьи — показать, что метаданные это мощный механизм, требующий выделения в отдельный компонент, который хотелось бы видеть в стандартной библиотеке С++.


E>...начал что-то понимать, но к средине статьи опять понимание куда-то исчезло...

Согласен. Мне уже по этому поводу люди высказали...

E>Имхо, удалось показать, что метаданные на шаблонах это слишком мощный (я бы даже сказал overkill) механизм. Что-то на нем очень круто как-то делается. Только вот что делается, почему это делается именно так, и стоило ли это делать именно так -- для меня остается загадкой. Вот серьезно, я не понял, почему на примере сериализации структур делается вывод о полезности метаинформации.


Сериализация — это классический пример использования метаданных.
Загляни в дотнет — там активно они используются (например, XmlSerializer). Существенное отличие в том, что в дотнете используются кодогенерация и компиляция на лету.

Задача была показать — что аналогичные возможности доступны и в С++.
Есть наметки как решить существующие проблемы (статья + пример).
Что бы сделать полноценную библиотеку нужно время. Если бы кто-нибудь за это взялся — я бы с удовольствием попользовался результатами

E>Поэтому, если задачей было показать необходимость подобного механизма в стандартной библиотеке C++, то, имхо, эта задача достигнута не была. Чесно говоря я вообще не понял, что за компонент должен быть в стандарной библиотеке и что этот компонент должен делать.

Стандартный способ описания и использования метаданных.

Если есть вопросы — я на них с удовольствием отвечу.

Влад
Использование метаданных в программах на языке C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 04.09.05 19:55
Оценка: 30 (6)
#Имя: FAQ.cpp.metadata
Здравствуй, Влад

E>>Имхо, удалось показать, что метаданные на шаблонах это слишком мощный (я бы даже сказал overkill) механизм. Что-то на нем очень круто как-то делается. Только вот что делается, почему это делается именно так, и стоило ли это делать именно так -- для меня остается загадкой. Вот серьезно, я не понял, почему на примере сериализации структур делается вывод о полезности метаинформации.


А>Сериализация — это классический пример использования метаданных.

А>Загляни в дотнет — там активно они используются (например, XmlSerializer). Существенное отличие в том, что в дотнете используются кодогенерация и компиляция на лету.

А>Задача была показать — что аналогичные возможности доступны и в С++.


Поскольку у меня есть нескоторый опыт
Автор: eao197
Дата: 24.01.05
, то могу сказать, что сериализация -- это классический пример весьма сложной задачи, решать которую можно разными способами. Один способ -- это создание метаданных вручную в коде программы. По этому пути пошли авторы boost::serialization, s11n.net и ты в своей статье. Если поднять обсуждения проблем сериализации и рефлекшена здесь и в форуме "C/C++ Прикладные вопросы", то такая точка зрения многим симпатична.

Еще один способ -- создание метаданных автоматически на основе парсинга C++ кода. Активным ее проповедником здесь является adontz (см., например, темы Проект сериализации [просьба высказаться]
Автор: adontz
Дата: 02.01.05
, Проект сериализации &mdash; 2 [просьба высказаться]
Автор: adontz
Дата: 08.01.05
, Проект сериализации &mdash; 3 [просьба высказаться]
Автор: adontz
Дата: 25.05.05
Проект Visual Generator
Автор: adontz
Дата: 07.07.05
).

Ну и еще один способ -- это наличие внешнего описания на Data Definition Language (DDL) из которого генерируется код сериализации/десериализации данных. Сторонником этого подхода являюсь я сам (в моем проекте ObjESSty так и происходит). По такому принципу работают ASN1 компиляторы (только там еще и описания C++ классов генерируются). Что-то подобное с IDL применяется в CORBA и Ice.

Лично мне последний способ представляется наиболее удобным, т.к. тогда мы получаем возможность делать более простые и, одновременно, более удобные описания. Например, на моем ObjESSty DDL описание структуры SPoint выглядело бы:
{type SPoint
    {attr x {of oess_1::int_t}}
    {attr y {of oess_1::int_t}}
}

(правда, ObjESSty пока не умеет делать XML-сериализацию, зато есть другие фишки). А из такого описания строится довольно-таки сложный вспомогательный код (пример которого можно посмотреть здесь
Автор: eao197
Дата: 19.04.05
).

Наличие отдельного, декларативного описания схемы сериализуемых данных позволяет получать дополнительные преимущества:
— простота описания (особенно в случае, когда сериализуемые C++ классы полностью генерируются по DDL описанию);
— возможность по одному описанию строить разные схемы сериализации/десериализации. Например, в твоем подходе для XML-сериализации сразу указываются имена XML элементов и атрибутов. И жестко фиксируются в метаданных. А что делать, если SPoint может быть сериализован в разных XML схемах и названия элементов и атрибутов должны быть разными? В DDL можно сделать что-то подобное:
{type SPoint
    {xml
        {scheme
            {name "http://www.superpuper.com/xml/schemas/scheme1" {alias "scheme1"}}
            {element "point"}}
        {scheme    {name "http://www.megapupersuper.com/schames/another" {alias "scheme2"}}
            {element "PT"}}
    }
    
    {attr x {of oess_1::int_t}
        {xml
            {scheme {alias "scheme1"}} {attr "x"}}
            {scheme {alias "scheme2"}} {element "x"}}
        }
    }
    {attr y {of oess_1::int_t}
        {xml
            {scheme {alias "scheme1"}} {attr "y"}}
            {scheme {alias "scheme2"}} {element "y"}}
        }
    }
}

И при генерации вспомогательного кода указывать, код для какой XML схемы нужно генерировать.
Или можно даже разнести описания самой структуры SPoint и способов ее отображения на XML:
{type SPoint
    {attr x {of oess_1::int_t}}
    {attr y {of oess_1::int_t}}
}

{xml-reflection {scheme "http://www.superpuper.com/xml/schemas/scheme1"}
    {type-reflection SPoint
        {element "point"}
        {attr x {as {attribute "x"}}}
        {attr y {as {attribute "y"}}}
    }
}

{xml-reflection {scheme "http://www.megapupersuper.com/schames/another"}
    {type-reflection SPoint
        {element "PT"}
        {attr x {as {element "x"}}}
        {attr y {as {element "y"}}}
    }
}

При этом дополнительные описания {xml-reflection} можно дополнять уже после того, как основной вспомогательный код для SPoint будет сгенерирован, скомпилирован и влинкован. Более того, можно даже сделать так, чтобы описания {xml-reflection} подгружались динамически и сериализация в новую XML схему выполнялась путем интерпретации описания {xml-reflection};
— возможность по DDL описанию генерировать код для поддержки этого типа в другом языке. Например, когда сериализованные C++ кодом данные должны быть прочитаны из Python или Ruby;
— возможность делать автоматические средства для трансформирования сериализованных данных при эволюции схемы данных.

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

Так что пример с применением предложенной тобой схемы сериализации лично для меня выглядит не очень удачным. Но это из-за того, что я сам сериализацией занимался и у меня другой взгляд на то, как это должно быть.

А>Есть наметки как решить существующие проблемы (статья + пример).

А>Что бы сделать полноценную библиотеку нужно время. Если бы кто-нибудь за это взялся — я бы с удовольствием попользовался результатами

Ну дык быблиотек для С++ сериализации не так уж и мало. Неужели ни одна не подходит?

E>>Поэтому, если задачей было показать необходимость подобного механизма в стандартной библиотеке C++, то, имхо, эта задача достигнута не была. Чесно говоря я вообще не понял, что за компонент должен быть в стандарной библиотеке и что этот компонент должен делать.

А>Стандартный способ описания и использования метаданных.

Имхо, нет такого понятия, как стандартный способ описания и использования метаданных. Поскольку метаданные привязаны к конкретной задаче. Для сериализации в XML -- нужен один тип метаданных, для сериализации в ASN1 -- совсем другой, для сериализации в YAML -- третий. А для создания более продвинутого аналога boost::signal (с возможностью выбора разных нитей для разных обработчиков сигналов) нужны будут совсем другие метаданные.

Один подход для их использования (который, имхо, сейчас очень популярен) -- это эксплуатация на полную катушку возможностей метапрограммирования в C++ с шаблонами. Лично мне этот подход не нравится. Потому, что получается очень трудновоспринимаемый код. Очень уж write-only код выходит. В boost когда-то предлагали включить библиотеку FSM (для описания конечных автоматов) -- это было нечто

А вот второй подход, основанный на использовании DSL (Domain Specific Language) мне гораздо более симпатичным. Создается простой язык для конкретной предметной области. Создается его транслятор и генератор вспомогательного кода. И создается необходимый набор библиотек для поддержки сгенерированного кода. Каждый компонентик оказывается относительно простым как в написании, так и в использовании. Но, что более важно, -- в сопровождении. Для сопровождения транслятора, созданного на основе, например, bison/flex, совсем не требуется гуру в области C++ шаблонов.

А еще интереснее то, что для DSL не обязательно создавать отдельные специализированные языки. Вполне возможно использовать некоторые существующие языки, которые способствуют метапрограммированию. Например, Lisp (см. Metaprogramming et al
Автор:
Дата: 09.07.05
, Re: Metaprogramming et al: Ruby?
Автор: eao197
Дата: 10.08.05
, Re[2]: Metaprogramming et al: Ruby?
Автор: eao197
Дата: 19.08.05
, Вот такой вот препроцессор.
Автор: c-smile
Дата: 20.08.05
, Re: Вот такой вот препроцессор.
Автор: eao197
Дата: 20.08.05
). Например, приведенные мной выше DDL-фрагмены можно было бы представить на Ruby чем-то вроде:
type :SPoint {
    attr :x, :oess_1::int_t
    attr :y, :oess_1::int_t
}

xml_reflection :scheme => "http://www.superpuper.com/xml/schemas/scheme1" { |s|
    s.type_reflection :SPoint, :element => "point" { |t|
        t.attr :x, :attribute => "x"
        t.attr :y, :attribute => "y"
    }
}

xml_reflection :scheme => "http://www.megapupersuper.com/schames/another" { |s|
    s.type_reflection :SPoint, :element => "PT" { |t|
        t.attr :x, :element => "x"
        t.attr :y, :element => "y"
    }
}

При этом нам не нужно писать ни лексический анализатор, ни синтаксический анализатор. Можно сразу создавать прикладные классы для хранения описания в Ruby коде и генерацию по этим описаниям C++ кода.

А>Если есть вопросы — я на них с удовольствием отвечу.


Да нет, вопросов как раз нет. Есть просто впечатление о статье, которое я и высказал. Надеюсь, оно окажется полезным.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Использование метаданных в программах на языке C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.09.05 12:10
Оценка: 10 (1)
Здравствуйте, eao197, Вы писали:

E>А вот второй подход, основанный на использовании DSL (Domain Specific Language) мне гораздо более симпатичным. Создается простой язык для конкретной предметной области. Создается его транслятор и генератор вспомогательного кода. И создается необходимый набор библиотек для поддержки сгенерированного кода. Каждый компонентик оказывается относительно простым как в написании, так и в использовании. Но, что более важно, -- в сопровождении. Для сопровождения транслятора, созданного на основе, например, bison/flex, совсем не требуется гуру в области C++ шаблонов.


E>А еще интереснее то, что для DSL не обязательно создавать отдельные специализированные языки. Вполне возможно использовать некоторые существующие языки, которые способствуют метапрограммированию. Например, Lisp (см. Metaprogramming et al
Автор:
Дата: 09.07.05
, Re: Metaprogramming et al: Ruby?
Автор: eao197
Дата: 10.08.05
, Re[2]: Metaprogramming et al: Ruby?
Автор: eao197
Дата: 19.08.05
, Вот такой вот препроцессор.
Автор: c-smile
Дата: 20.08.05
, Re: Вот такой вот препроцессор.
Автор: eao197
Дата: 20.08.05
).


Вот как раз по следам этих обсуждений (а так же задачки, предложенной вот здесь
Автор: AndrewVK
Дата: 13.07.05
) я сегодня решился применить кодогенерацию с помощь простенького DSL. Нужно мне было создать C++ класс, который бы хранил несколько полей (с перспективой увеличения их числа в ближайшем будущем). Проблема была в том, что для каждого поля нужно было иметь четыре метода (например, для поля с именем source_addr_ton):
bool is_source_addr_ton_present() const;
oess_1::uchar_t source_addr_ton() const;
void set_source_addr_ton( oess_1::uchar_t v );
void drop_source_addr_ton();


Все еще усугублялось тем, что признак наличия актуального значения у поля должен быть выставлен в специальной битовой маске. И если вызывается метод getter, а бит в этой маске не выставлен, то getter должен порождать исключение. Соответственно, метод setter должен выставлять соответствующий бит в битовой маске. Т.е. что-то типа:
bool is_source_addr_ton_present() const { return ( 0 != ( m_fields_bit_mask & 1 ) ); }
oess_1::uchar_t source_addr_ton() const {
    if( !is_source_addr_ton_present() )
        throw std::runtime_error( "source_addr_ton: no actual value" );
    return m_source_addr_ton;
}
void set_source_addr_ton( oess_1::uchar_t v ) {
    m_source_addr_ton = v;
    m_fields_bit_mask |= 1;
}
void drop_source_addr_ton() {
    m_fields_bit_mask &= ~1;
}


Можно было бы применить обычный copy-paste. А затем править названия полей и методов, ожидая, что где-то что-то окажется забытым.
Можно было бы написать пару макросов и использовать их:
class submit_deliver_t
{
    public :
        DECL_FIELD( source_addr_ton, oess_1::uchar_t, 0, 1 )
        DECL_FIELD( source_addr_npi, oess_1::uchar_t, 0, 2 )
        DECL_FIELD( dest_addr_ton, oess_1::uchar_t, 0, 4 )
        ...
};

IMPL_FIELD( source_addr_ton, oess_1::uchar_t, 0, 1 )
IMPL_FIELD( source_addr_npi, oess_1::uchar_t, 0, 2 )
IMPL_FIELD( dest_addr_ton, oess_1::uchar_t, 0, 4 )


Да только макросы получаются непрозрачными для инструментов типа ctags и doxygen.

В общем, решился я на применение такого Ruby описания (файл submit_deliver.rb):
require 'mbsms_2/smpp/submit_deliver_gen'

submit_deliver(
        "mbsms_2/smpp/h/submit_deliver.detail.hpp",
        "mbsms_2/smpp/submit_deliver.detail.cpp" ) do |c|
    c.field :name => :source_addr_ton,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x1,
            :default => 0

    c.field :name => :source_addr_npi,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x2,
            :default => 0

    c.field :name => :dest_addr_ton,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x4,
            :default => 0

    c.field :name => :dest_addr_npi,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x8,
            :default => 0

    c.field :name => :esm_class,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x10,
            :default => 0

    c.field :name => :protocol_id,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x20,
            :default => 0

    c.field :name => :data_coding,
            :type => "oess_1::uchar_t",
            :bit_mask => 0x40,
            :default => 0
end


Для его использования добавил в проектный файл несколько строчек:
generator( Mxx_ru::Makestyle_generator.new(
    [ "mbsms_2/smpp/h/submit_deliver.detail.hpp",
        "mbsms_2/smpp/submit_deliver.detail.cpp" ],
    [ "mbsms_2/smpp/submit_deliver.rb",
        "mbsms_2/smpp/submit_deliver_gen.rb" ],
    [ "ruby mbsms_2/smpp/submit_deliver.rb" ] ) )

т.е. файлы submit_deliver.detail.hpp и submit_deliver.detail.cpp перестраиваются при изменении submit_deliver.rb или submit_deliver_gen.rb. Перестройка выполняется с помощью Ruby и скрипта submit_deliver.rb.

Автоматически генерируемые файлы submit_deliver.detail.* используются очень просто:
// Файл submit_deliver.hpp
/*!
    \file
    \brief Класс для хранения опциональных SMPP полей для
        submit_sm/deliver_sm/data_sm PDU.
*/

#if !defined( MBSMS_2__SMPP__SUBMIT_DELIVER_HPP )
#define MBSMS_2__SMPP__SUBMIT_DELIVER_HPP

#include <mbsms_2/h/declspec.hpp>

#include <oess_1/stdsn/h/serializable.hpp>

namespace mbsms_2
{

namespace smpp
{

#include "submit_deliver.detail.hpp"

} /* namespace smpp */

} /* namespace mbsms_2 */

#endif


// Файл submit_deliver.cpp
/*!
    \file
    \brief Класс для хранения опциональных SMPP полей для
        submit_sm/deliver_sm/data_sm PDU.
*/

#include <mbsms_2/smpp/h/submit_deliver.hpp>

#include <oess_1/stdsn/h/inout_templ.hpp>

namespace mbsms_2
{

namespace smpp
{

#include "submit_deliver.detail.cpp"

#include "submit_deliver.ddl.cpp"

} /* namespace smpp */

} /* namespace mbsms_2 */


В результате получается вот такое описание класса (фрагмент):
/*!
    Класс для хранения опциональных значений SMPP-полей для
    submit_sm/deliver_sm/data_sm PDU.

    Поле считается имеющим актуальное значение, если соответствующий
    метод is_*_present возвращает true. В противном случае поле считается
    не заданным и обращение к нему будет приводить к возникновению
    исключения std::exception.
*/
class MBSMS_2_TYPE submit_deliver_t
    :    public oess_1::stdsn::serializable_t
    {
        OESS_SERIALIZER_EX( submit_deliver_t, MBSMS_2_TYPE )
    public :
        /*!
            Конструктор по умолчанию.

            Все поля считаются не имеющими актуального значения.
        */
        submit_deliver_t();
        virtual ~submit_deliver_t();

        /*!
            \return true, если значение для поля source_addr_ton задано.
        */
        bool
        is_source_addr_ton_present() const;
        /*!
            \return значение поля source_addr_ton.
            \throw std::exception при попытке получить значение отсутствующего
            поля.
        */
        oess_1::uchar_t
        source_addr_ton() const;
        /*!
            Установить значение поля source_addr_ton.

            Одновременно выставляется признак того, что поле задано.
        */
        void
        set_source_addr_ton( oess_1::uchar_t v );
        /*!
            Сбросить признак того, что поле source_addr_ton задано.
        */
        void
        drop_source_addr_ton();

        /*!
            \return true, если значение для поля source_addr_npi задано.
        */
        bool
        is_source_addr_npi_present() const;
        /*!
            \return значение поля source_addr_npi.
            \throw std::exception при попытке получить значение отсутствующего
            поля.
        */
        oess_1::uchar_t
        source_addr_npi() const;
...

и вот такая его реализация (фрагмент):
submit_deliver_t::submit_deliver_t()
    :    m_fields_bit_mask( 0 )
    ,    m_source_addr_ton( 0 )
    ,    m_source_addr_npi( 0 )
    ,    m_dest_addr_ton( 0 )
    ,    m_dest_addr_npi( 0 )
    ,    m_esm_class( 0 )
    ,    m_protocol_id( 0 )
    ,    m_data_coding( 0 )

    {}

submit_deliver_t::~submit_deliver_t()
    {}

bool
submit_deliver_t::is_source_addr_ton_present() const
    {
        return ( 1 == ( m_fields_bit_mask & 1 ) );
    }
oess_1::uchar_t
submit_deliver_t::source_addr_ton() const
    {
        if( !is_source_addr_ton_present() )
            throw std::runtime_error( "source_addr_ton: no actual value" );
        return m_source_addr_ton;
    }
void
submit_deliver_t::set_source_addr_ton( oess_1::uchar_t v )
    {
        m_source_addr_ton = v;
        m_fields_bit_mask |= 1;
    }
void
submit_deliver_t::drop_source_addr_ton()
    {
        m_fields_bit_mask &= ~1;
    }
bool
submit_deliver_t::is_source_addr_npi_present() const
    {
        return ( 2 == ( m_fields_bit_mask & 2 ) );
    }
oess_1::uchar_t
submit_deliver_t::source_addr_npi() const
    {
        if( !is_source_addr_npi_present() )
            throw std::runtime_error( "source_addr_npi: no actual value" );
        return m_source_addr_npi;
    }
void
submit_deliver_t::set_source_addr_npi( oess_1::uchar_t v )
    {
        m_source_addr_npi = v;
        m_fields_bit_mask |= 2;
    }
void
submit_deliver_t::drop_source_addr_npi()
    {
        m_fields_bit_mask &= ~2;
    }
...


Самое прикольное, что doxygen по этому делу генерирует нормальную документацию

В итоге получилось, что я написал ~230 строк генерирующего Ruby скрипта submit_deliver_gen.rb, плюс 42 строки DSL-я submit_deliver.rb. И получил ~430 строк сгенерированного C++ текста. Правда, потратил я на написание этого скрипта порядка 1.5 часов. Но, имхо, за это получил инструментик, который легко поможет мне как добавлять новые поля, так и менять реализацию работы с полями в генерируемом классе.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[2]: Использование метаданных в программах на языке C++
От: Tom Россия http://www.RSDN.ru
Дата: 08.09.05 14:21
Оценка:
E>Самое прикольное, что doxygen по этому делу генерирует нормальную документацию
не это не самое прикольное

E>В итоге получилось, что я написал ~230 строк генерирующего Ruby скрипта submit_deliver_gen.rb, плюс 42 строки DSL-я submit_deliver.rb. И получил ~430 строк сгенерированного C++ текста. Правда, потратил я на написание этого скрипта порядка 1.5 часов. Но, имхо, за это получил инструментик, который легко поможет мне как добавлять новые поля, так и менять реализацию работы с полями в генерируемом классе.

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

Кодировать нужно так, как будто человек который будет сопровождать этот код — маньяк, и он знает где вы живёте! (c) McConnell

... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Народная мудрось
всем все никому ничего(с).
Re[3]: Использование метаданных в программах на языке C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.09.05 14:35
Оценка: +1
Здравствуйте, Tom, Вы писали:

E>>В итоге получилось, что я написал ~230 строк генерирующего Ruby скрипта submit_deliver_gen.rb, плюс 42 строки DSL-я submit_deliver.rb. И получил ~430 строк сгенерированного C++ текста. Правда, потратил я на написание этого скрипта порядка 1.5 часов. Но, имхо, за это получил инструментик, который легко поможет мне как добавлять новые поля, так и менять реализацию работы с полями в генерируемом классе.

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

Tom>

Tom>Кодировать нужно так, как будто человек который будет сопровождать этот код — маньяк, и он знает где вы живёте! (c) McConnell


Не вижу в этом случае никаких проблем с дальнейшим сопровождением.
Если бы я сделал пару-тройку многоярусных макросов и оставил кусок кода, который эти макросы использует, вот тогда, имхо, было бы больше шансов получить в спину пару ласковых слов. А так -- нормальный C++-ный код, с комментариями . Что хочешь, то и делай. Хочешь -- просто возьми результаты генерации, выброси Ruby DSL и правь дальше однаждый сгенерированный C++ный код. Хочешь -- переделай все под макросы, хочешь -- напиши другой генератор на Python-е и XML -- полная свобода.

Кроме того, имхо, разобраться в небольшом Ruby-скрипте гораздо проще, чем в сотне-другой copy-paste кода. Или каких нибудь шаблонных наворотах.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Использование метаданных в программах на языке C++
От: Cyberax Марс  
Дата: 08.09.05 15:08
Оценка:
Tom wrote:

> Кодировать нужно так, как будто человек который будет сопровождать

> этот код — маньяк, и он знает где вы живёте! (c) McConnell

Мой коллега добавил: "Потому, что это действительно так".

--
С уважением,
Alex Besogonov (alexy@izh.com)
Posted via RSDN NNTP Server 2.0 beta
Sapienti sat!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.