Аннотация:
В статье предложено решение унификации функций доступа к внутренним переменным класса, рассмотрен вопрос локализации в одном файле типов переменных класса. Предложенное решение может быть актуальным для классов, содержащих большое количество внутренних переменных.
У меня вопрос.
Допустим, в новой спецификации поменяли тип одного из полей с двух на четырех-байтный. Ok, для этого поля меняем параметр шаблона ParameterFactory.
Но мне нужно оставить совместимость и со старой версией спецификации, как быть?
Re[2]: Автоматическая генерация интерфейсов классов
5er>У меня вопрос. 5er>Допустим, в новой спецификации поменяли тип одного из полей с двух на четырех-байтный. Ok, для этого поля меняем параметр шаблона ParameterFactory. 5er>Но мне нужно оставить совместимость и со старой версией спецификации, как быть?
К сожалению не будут они полностью совместимыми. Последствия такого изменения надо рассматривать в каждом конкретном случае отдельно. Примером может быть параметр TTG (transmit/receive transition gap -- задержка времени переключения антенны с режима передачи на приём) в сообщении DCD. В стандарте IEEE 802.16-2004 размер поля был 1 байт, через пять лет внесли изменения в стандарт и в IEEE 802.16-2009 размер поля стал 2 байта для станций, работающих во временном дуплексе, и 4 байта для станций, работающих в частотном полудуплексе.
Сериализация сообщения происходит на базовой станции, которая посылает в эфир сообщение DCD с обновлённым полем TTG, например, длиной 2 байта. Приём DCD происходит на абонентской станции, к примеру, программное обеспечение которой не было обновлено, и она ожидает размер поля TTG 1 байт. Далее возможно несколько сценариев:
Сценарий 1. Разработчики абонентской станции предвидели, что стандарт новый и заложили динамическое формирование параметров. Встретив в бинарном потоке байт "тип" 0х07, и следующий байт "длина параметра" 0х02, создают через new() двухбайтовую структуру.
Сценарий 2. Под поле TTG жестко выделен 1 байт. Если значение превысит 255, произойдёт срезка.
Сценарий 3. Приёмник контролирует значение длины поля и ожидает размер поля TTG 1 байт. Произойдёт исключение в режиме исполнения (run-time), (как это сейчас реализовано в моём случае) проигнорирует это поле с занесением в лог, посчитав его ошибочным. Здесь всё зависит от принятой политики обработки исключений.
В данном случае самый безболезненный пример Сценария 1 -- полная совместимость.
то произойдёт срезка (Сценарий 2). Хуже того, компилятор, например gcc 4.6.2 "g++ -O0 -g3 -Wall -c -fmessage-length=0 -o src\test_info.o ..\src\test_info.cpp", даже не предупредит о возможных проблемах.
В таком случае я бы рекомендовал переход к POD типам осуществлять следующим способом, который не влечёт никаких накладных расходов:
Здравствуйте, Чигринец Владислав Александрович, Вы писали:
ЧВА>Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии.
DcdMsgType,
DcdConfigChangeCount,
//for TVL parameters:
DcdEirp = 2,
DcdFrequency = 12
public Parameter<DcdParameterIds, DcdMsgType>,
public Parameter<DcdParameterIds, DcdConfigChangeCount>,
public Parameter<DcdParameterIds, DcdEirp>,
public Parameter<DcdParameterIds, DcdFrequency>
чем это, лучше чем нормальный простой аггрегирующий класс (с нормальными типами полей, а не short/char/int/long как у вас) + сериализирующая функция?
И в вашем случае, и в случае с простым аггрегирующим классом, инфа дублируется дважды.
5er>У меня вопрос. 5er>Допустим, в новой спецификации поменяли тип одного из полей с двух на четырех-байтный. Ok, для этого поля меняем параметр шаблона ParameterFactory. 5er>Но мне нужно оставить совместимость и со старой версией спецификации, как быть?
совместимости не будет
даже если взять шаблон
template <int>
class Storage;
то классы:
Storage<1>
и
Storage<2>
это разные типы.
можно писать свои же конверторы, но типы изначально разные
Re[2]: Автоматическая генерация интерфейсов классов
Здравствуйте, Piko, Вы писали:
P>Здравствуйте, Чигринец Владислав Александрович, Вы писали:
ЧВА>>Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии.
P>
Как говорится, за деревьями леса не видно: чем проще пример, тем легче объяснить идею, но, с другой стороны, тем нелепей могут быть методики решения проблемы -- "здесь всё просто, зачем ещё что-то городить?!." Конечно, если структура простая, состоит из простых типов, то класс не нужен, передаём struct и обращаемся по имени к полям структуры. Ни getter'ы ни setter'ы в таком случае не нужны, и здесь я с Вами полностью согласен.
Но что даёт нам объявление имён в перечислении? Вопервых можно автоматически регистрировать обработчики, как это сделано в статье Нетривиальное использование шаблонов. Часть первая., ссылка на которую дана у меня в статье (только будьте внимательны при чтении этой статьи, т.к. html несколько исказил в ней исходные коды). На этом принципе у меня построен десериализатор, для которого не хватило формата статьи. Читабельное имя нужно только для программиста, просматривающего код. Для компилятора и логики работы программы оно не несёт никакой информации. Развивая дальше мысль, скажу, что доступ к параметру, не завязанный на его имя, облегчает строить параметрические (generic) алгоритмы.
P>2. инфа дублируется, DRY нарушен:
P>
P> DcdMsgType,
P> DcdConfigChangeCount,
P> //for TVL parameters:
P> DcdEirp = 2,
P> DcdFrequency = 12
P> public Parameter<DcdParameterIds, DcdMsgType>,
P> public Parameter<DcdParameterIds, DcdConfigChangeCount>,
P> public Parameter<DcdParameterIds, DcdEirp>,
P> public Parameter<DcdParameterIds, DcdFrequency>
P>
P>чем это, лучше чем нормальный простой аггрегирующий класс (с нормальными типами полей, а не short/char/int/long как у вас) + сериализирующая функция? P>И в вашем случае, и в случае с простым аггрегирующим классом, инфа дублируется дважды.
Тоже согласен, ибо выглядит это некрасиво и про дублирование всё верно. Но я неоднократно упоминал как в самой статье (второе предложение заключения), так и здесь на форуме, что дублирования и наследования можно избежать. Наверно надо привести пример, т.к. утверждение получается голословным и не воспринимается. Вот далеко не изящный пример, написаный "на коленке", в котором избегаем дублирование без решения проблемы с наследованием:
enum DcdParameterIds
{
DcdMsgType,
DcdConfigChangeCount,
//for TVL parameters:
DcdEirp = 2,
DcdFrequency = 12
, DCD_ID_NR
};
template<>
class MessageSet<DcdId>:
public ParameterAutoAdd<DCD_ID_NR>
{};
template<DcdParameterIds _IdMax>
class ParameterAutoAdd :
public Parameter<DcdParameterIds, static_cast<DcdParameterIds>(_IdMax - 1)>,
public ParameterAutoAdd<static_cast<DcdParameterIds>(_IdMax - 1)>
{};
template<>
class ParameterAutoAdd<static_cast<DcdParameterIds>(0)>
public Parameter<DcdParameterIds, static_cast<DcdParameterIds>(0)>
{};
Всё, теперь добавляем новое имя параметра, например new_mem_var, как элемент перечисления перед DCD_ID_NR, и определяем его характеристики в классе Parameter<DcdParameterIds, new_mem_var>. Никакого дублирования, компилятор сам добавит этот параметр в класс MessageSet.
Понял о чём идёт речь. Ответ мой будет кратким: "Избегайте макросов". У меня в статье есть ссылка номер 2 на книгу "Саттер Г., Александреску А. Стандарты программирования на С++. 101 правило и рекомендация", посмотрите рекомендацию номер 16 на странице 44 (желательно посмотреть её развёрнутое обоснование, в http://www.rus-lib.com/book/355501 лишь аннотация к рекомендации. От макросов не уйти в С программировании, но в С++ со многими задачами справляются шаблоны.
Re[4]: Автоматическая генерация интерфейсов классов
Здравствуйте, смит, Вы писали:
С>... P>>>3. вы слышали о технике X-Macros ( http://stackoverflow.com/questions/264269/what-is-a-good-reference-documenting-patterns-of-use-of-x-macros-in-c-or-possib ) ? С>>сейчас почитаю,.. С>Понял о чём идёт речь. Ответ мой будет кратким: "Избегайте макросов". У меня в статье есть ссылка номер 2 на книгу "Саттер Г., Александреску А. Стандарты программирования на С++. 101 правило и рекомендация", посмотрите рекомендацию номер 16 на странице 44 (желательно посмотреть её развёрнутое обоснование, в http://www.rus-lib.com/book/355501 лишь аннотация к рекомендации. От макросов не уйти в С программировании, но в С++ со многими задачами справляются шаблоны.
знаю я все ваши аргументы про макросы, и Саттера и Аллександреску я читал.
Макросы нужно использовать обоснованно, также как и шаблоны.
И, если макросы многократно упрощают реализацию и интерфейс по сравнению с шаблонами, то почему бы и нет?
Re[3]: Автоматическая генерация интерфейсов классов
Здравствуйте, смит, Вы писали:
ЧВА>>>Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии. P>>
P>>1. зачем здесь вообще getter'ы и setter'ы ? С>Как говорится, за деревьями леса не видно: чем проще пример, тем легче объяснить идею, но, с другой стороны, тем нелепей могут быть методики решения проблемы -- "здесь всё просто, зачем ещё что-то городить?!." Конечно, если структура простая, состоит из простых типов, то класс не нужен, передаём struct и обращаемся по имени к полям структуры. Ни getter'ы ни setter'ы в таком случае не нужны, и здесь я с Вами полностью согласен.
Если вы сами знаете, что они вам не нужны, то зачем в статье оставили их?
Ведь вы даже это используете как "недостаток":
Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии. Итого восемь функций интерфейса доступа.
:::
Другим недостатком явного объявления типа параметра является то, что изменение размера переменной или ее типа в исходном техническом задании влекут за собой соответствующие изменения в листингах 1 и 2, а именно: в объявлении переменной, в интерфейсах доступа к ней, и во всех местах кода, где она назначается.
Если бы у вас использовались нормальные типы, а не char/short/int/long:
1. не нужны были бы getter'ы/setter'ы. Вы ведь их тут влепили на случай всякий валидаций, инвариантов?
2. Изменение типа параметра не "повлекло бы изменения в листингах 1 и 2", так как изменение нижележащих типов (внутри аггрегируемых классов) в интерфейсе просто были бы не видны.
С>Но что даёт нам объявление имён в перечислении? Вопервых можно автоматически регистрировать обработчики, как это сделано в статье Нетривиальное использование шаблонов. Часть первая., ссылка на которую дана у меня в статье (только будьте внимательны при чтении этой статьи, т.к. html несколько исказил в ней исходные коды). На этом принципе у меня построен десериализатор, для которого не хватило формата статьи. Читабельное имя нужно только для программиста, просматривающего код. Для компилятора и логики работы программы оно не несёт никакой информации.
тоже самое дало бы: аггрегирующий класс + сереализирующая функция (на самом деле даже не функция, нужно просто представить схему данных в таком формате, в котором её можно было бы многократно использовать в разных местах. сереализирующая функция может автоматом "генерироваться" на основе этой схемы. и тут как раз метапрограммирование уместно)
С>Развивая дальше мысль, скажу, что доступ к параметру, не завязанный на его имя, облегчает строить параметрические (generic) алгоритмы.
ну так определите простой аггрегирующий класс + схема данных в каком либо формате: и интерфейс для пользователя будет простым, и что главное намного менее подверженный ошибкам, и схему можно обходить как только вздумается.
P>>чем это, лучше чем нормальный простой аггрегирующий класс (с нормальными типами полей, а не short/char/int/long как у вас) + сериализирующая функция? P>>И в вашем случае, и в случае с простым аггрегирующим классом, инфа дублируется дважды. С>Тоже согласен, ибо выглядит это некрасиво и про дублирование всё верно. Но я неоднократно упоминал как в самой статье (второе предложение заключения), так и здесь на форуме, что дублирования и наследования можно избежать. Наверно надо привести пример, т.к. утверждение получается голословным и не воспринимается. Вот далеко не изящный пример, написаный "на коленке", в котором избегаем дублирование без решения проблемы с наследованием:
:: С>Всё, теперь добавляем новое имя параметра, например new_mem_var, как элемент перечисления перед DCD_ID_NR, и определяем его характеристики в классе Parameter<DcdParameterIds, new_mem_var>. Никакого дублирования, компилятор сам добавит этот параметр в класс MessageSet.
дублирование осталось, но уже меньше: нужно указывать первый (либо 0) и последний (либо следующий за последним) элементы. можно конечно и не указывать и обходить заведомо больший диапазон compile time, но это то ещё уродство.
Также, нет никакой гарантии для пользователя что для всех элементов enum'а есть специализация parameter<>, что нет лишней специализации (например DcdEirp+3 ). В общем error-prone
А главное вы не ответили чем это всё лучше простого аггрегирующего класса (с нормальной реализацией, а не как у вас с getters and setters).
P>>4. вы слышали о code generation? С>может быть, был бы благодарен за ссылочку.
Код C++ можно генерировать программой/скриптом
1. Делаете описание схемы с помощью какого-нибудь подходящего формата, да хоть простого xml.
2. Парсите xml, естественно не вручную.
3. Генерируете код (необязательно весь. при этом до сих пор можно использовать рукописные шаблоны, так где это уместно)
А главное, результат будет на порядок более надёжный и на порядок более лёгкий в поддержке и использовании. Как следствие, намного более дешёвый в плане $$$$
Re[5]: Автоматическая генерация интерфейсов классов
Здравствуйте, Piko, Вы писали:
P>Здравствуйте, смит, Вы писали:
С>>... P>>>>3. вы слышали о технике X-Macros ( http://stackoverflow.com/questions/264269/what-is-a-good-reference-documenting-patterns-of-use-of-x-macros-in-c-or-possib ) ? С>>>сейчас почитаю,.. С>>Понял о чём идёт речь. Ответ мой будет кратким: "Избегайте макросов". У меня в статье есть ссылка номер 2 на книгу "Саттер Г., Александреску А. Стандарты программирования на С++. 101 правило и рекомендация", посмотрите рекомендацию номер 16 на странице 44 (желательно посмотреть её развёрнутое обоснование, в http://www.rus-lib.com/book/355501 лишь аннотация к рекомендации. От макросов не уйти в С программировании, но в С++ со многими задачами справляются шаблоны.
P>знаю я все ваши аргументы про макросы, и Саттера и Аллександреску я читал. P>Макросы нужно использовать обоснованно, также как и шаблоны. P>И, если макросы многократно упрощают реализацию и интерфейс по сравнению с шаблонами, то почему бы и нет?
Я не призываю к священной войне против макросов, и нет у меня фанатизма по отношению к шаблонам. Макросы активно применяются в библиотеке boost, у Алксандреску линеаризация создания списков типов и диагностика статических проверок построены на макросах. Просто, зная недостатки макросов, а в вышеупомянутой ркомендации Саттер их красноречиво расписал, цитата "...Основная проблема с макросами С++ заключается в том, что они выглядят гораздо привлекательнее, чем являются таковыми на самом деле...", лично отдаю предпочтение шаблонам. Здесь есть полный текст: http://lib.ec/b/355501/read
Макросы тоже применял для генерации классов, но это был случай, когда надо было скрыть некоторые детали реализации библиотеки (недостаток шаблонов в том, что код нельзя скрыть в *.срр файле). Пришлось скрывать через pimpl-идиому и макросы.
Re[6]: Автоматическая генерация интерфейсов классов
Здравствуйте, смит, Вы писали:
P>>>>>3. вы слышали о технике X-Macros ( http://stackoverflow.com/questions/264269/what-is-a-good-reference-documenting-patterns-of-use-of-x-macros-in-c-or-possib ) ? С>>>>сейчас почитаю,.. С>>>Понял о чём идёт речь. Ответ мой будет кратким: "Избегайте макросов". У меня в статье есть ссылка номер 2 на книгу "Саттер Г., Александреску А. Стандарты программирования на С++. 101 правило и рекомендация", посмотрите рекомендацию номер 16 на странице 44 (желательно посмотреть её развёрнутое обоснование, в http://www.rus-lib.com/book/355501 лишь аннотация к рекомендации. От макросов не уйти в С программировании, но в С++ со многими задачами справляются шаблоны. P>>знаю я все ваши аргументы про макросы, и Саттера и Аллександреску я читал. P>>Макросы нужно использовать обоснованно, также как и шаблоны. P>>И, если макросы многократно упрощают реализацию и интерфейс по сравнению с шаблонами, то почему бы и нет?
С>Я не призываю к священной войне против макросов, и нет у меня фанатизма по отношению к шаблонам.
А я как бы тоже не призываю просто в этом конкретном случае пара макросов уменьшило бы повторяемость
С>Макросы активно применяются в библиотеке boost, у Алксандреску линеаризация создания списков типов и диагностика статических проверок построены на макросах.Просто, зная недостатки макросов, а в вышеупомянутой ркомендации Саттер их красноречиво расписал, цитата "...Основная проблема с макросами С++ заключается в том, что они выглядят гораздо привлекательнее, чем являются таковыми на самом деле...",
Я же сказал, я знаю все ваши аргументы про макросы
С>лично отдаю предпочтение шаблонам.
и? я тоже предпочитаю шаблоны, а не макросы, но в некоторых случаях макросы необходимы
С>Здесь есть полный текст: http://lib.ec/b/355501/read
я вам показал технику X-Macro, использование которой привело бы, к более рациональной реализации и интерфейсу, я не пойму к чему вы начали рассказывать про ваш вкусы и опыт работы с макросами
Re[4]: Автоматическая генерация интерфейсов классов
Здравствуйте, Piko, Вы писали:
P>Здравствуйте, смит, Вы писали:
ЧВА>>>>Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии. P>>>
P>>>1. зачем здесь вообще getter'ы и setter'ы ?
... P>Если бы у вас использовались нормальные типы, а не char/short/int/long: P>1. не нужны были бы getter'ы/setter'ы. Вы ведь их тут влепили на случай всякий валидаций, инвариантов? P>2. Изменение типа параметра не "повлекло бы изменения в листингах 1 и 2", так как изменение нижележащих типов (внутри аггрегируемых классов) в интерфейсе просто были бы не видны.
... С>>Всё, теперь добавляем новое имя параметра, например new_mem_var, как элемент перечисления перед DCD_ID_NR, и определяем его характеристики в классе Parameter<DcdParameterIds, new_mem_var>. Никакого дублирования, компилятор сам добавит этот параметр в класс MessageSet.
P>дублирование осталось, но уже меньше: нужно указывать первый (либо 0) и последний (либо следующий за последним) элементы. можно конечно и не указывать и обходить заведомо больший диапазон compile time, но это то ещё уродство. P>Также, нет никакой гарантии для пользователя что для всех элементов enum'а есть специализация parameter<>, что нет лишней специализации (например DcdEirp+3 ). В общем error-prone
Последний элемент перечисления надо указывать! Лишних специализаций не будет, либо класс будет пустым без вопрощения в объект, либо будет регистрироваться класс по умолчанию, шаблонами сделать это легко. Время компиляции увеличится. Генерация кода через макросы и code generation тоже не уменьшают время пре-компиляции.
P>А главное вы не ответили чем это всё лучше простого аггрегирующего класса (с нормальной реализацией, а не как у вас с getters and setters).
Приведите, пожалуйста, пример Вашего кода, может я неправильно интерпретирую Ваши мысли.
Могу сделать инкапсуляцию шаблонами не через наследование, а через механизм включения. Предыдущий пример был лишь примером "на скорую руку", как избавиться от дублирования кода. Меня терзают смутные сомнения, что в контексте решения Ваших задач идеи, изложенные в статье, не имеют практической значимости. Вероятно мне надо дальше дописывать статью, чтобы показать выгоды от использования предложенного интерфейса доступа (но с этим не так быстро). Повторюсь, без использования шаблонных алгоритмов при дальнейшей работе с классом Message<>, большого смысла в предложенном мной интерфейсе доступа действительно нет. Надеюсь у Вас нет "аллергии" на шаблоны?
P>>>4. вы слышали о code generation? С>>может быть, был бы благодарен за ссылочку. P>Код C++ можно генерировать программой/скриптом P>1. Делаете описание схемы с помощью какого-нибудь подходящего формата, да хоть простого xml. P>2. Парсите xml, естественно не вручную. P>3. Генерируете код (необязательно весь. при этом до сих пор можно использовать рукописные шаблоны, так где это уместно)
P>А главное, результат будет на порядок более надёжный и на порядок более лёгкий в поддержке и использовании. Как следствие, намного более дешёвый в плане $$$$
Вам кажется, что так лучше и надёжней... Вероятно отпугивает не простой код, требующий квалификации для развития и поддержки... Но мы же не ищем лёгких путей!? ... Важны идеи!.. Прийдёт час и они окажутся востребованы... Всё новое рождается в муках... Методику генерации С++ кода из xml файлов с помощью xslt преобразования тоже применяем.
Re[5]: Автоматическая генерация интерфейсов классов
Здравствуйте, смит, Вы писали:
ЧВА>>>>>Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии. P>>>>
P>>>>1. зачем здесь вообще getter'ы и setter'ы ? С>... P>>Если бы у вас использовались нормальные типы, а не char/short/int/long: P>>1. не нужны были бы getter'ы/setter'ы. Вы ведь их тут влепили на случай всякий валидаций, инвариантов? P>>2. Изменение типа параметра не "повлекло бы изменения в листингах 1 и 2", так как изменение нижележащих типов (внутри аггрегируемых классов) в интерфейсе просто были бы не видны. С>Частично на это я ответил здесь... нет?..
вы делаете акцент на политику хранения.
А вы можете перевести практические варианты хранения о которых вы думаете?
И чем они лучше чем простой аггрегирующий класс?
Если вы делаете абстракцию на политику хранения, ведь значит что вы предполагаете разные варианты политики хранения.
С>... С>>>Всё, теперь добавляем новое имя параметра, например new_mem_var, как элемент перечисления перед DCD_ID_NR, и определяем его характеристики в классе Parameter<DcdParameterIds, new_mem_var>. Никакого дублирования, компилятор сам добавит этот параметр в класс MessageSet. P>>дублирование осталось, но уже меньше: нужно указывать первый (либо 0) и последний (либо следующий за последним) элементы. можно конечно и не указывать и обходить заведомо больший диапазон compile time, но это то ещё уродство. P>>Также, нет никакой гарантии для пользователя что для всех элементов enum'а есть специализация parameter<>, что нет лишней специализации (например DcdEirp+3 ). В общем error-prone С>Лишних специализаций не будет,
где гарантии того, что кто-нибудь не сделает лишнюю специализацию, для числа которого нет в enum, например "DcdEirp+3" ?
С>либо класс будет пустым без вопрощения в объект, либо будет регистрироваться класс по умолчанию,
как будет регистрироваться класс по-умолчанию, когда например программист забыл сделать специализацию parameter для DcdConfigChangeCount ?
С>шаблонами сделать это легко. Время компиляции увеличится. Генерация кода через макросы и code generation тоже не уменьшают время пре-компиляции.
А я ничего не говорил про время компиляции. я наоборот готов жертвовать временем компиляции ради надёжности
P>>А главное вы не ответили чем это всё лучше простого аггрегирующего класса (с нормальной реализацией, а не как у вас с getters and setters). С>Приведите, пожалуйста, пример Вашего кода, может я неправильно интерпретирую Ваши мысли.
с getter'ами, setter'ами (ну не прям тут, но вы сказали что setter'ы нужны), с конкретным low-level типами.
Сами же сказали что в этом коде проблемы с getters/setters, и low-level типами. Показали нагромождённое решение.
Я же предлагаю вам подумать об более простом и элегантном способе:
в котором нет тех двух проблем с getters/setters и привязки к low-level типам, которыми вы оправдываете свою статью.
С>Могу сделать инкапсуляцию шаблонами не через наследование, а через механизм включения. Предыдущий пример был лишь примером "на скорую руку", как избавиться от дублирования кода. Меня терзают смутные сомнения, что в контексте решения Ваших задач идеи, изложенные в статье, не имеют практической значимости. Вероятно мне надо дальше дописывать статью, чтобы показать выгоды от использования предложенного интерфейса доступа (но с этим не так быстро).
Я где-нибудь здесь говорил про решение моих задач?
С>Повторюсь, без использования шаблонных алгоритмов при дальнейшей работе с классом Message<>, большого смысла в предложенном мной интерфейсе доступа действительно нет.
То есть цель вашего интерфейса: использование шаблонных алгоритмов?
Не решение конкретных задач, а именно использование техники?
С>Надеюсь у Вас нет "аллергии" на шаблоны?
А с чего вы взяли, что у меня может быть аллергия на шаблоны?
То что я вам указал на то, что ваша реализация неадекватная (пусть она и использует шаблоны), разве говорит о том, что мне не нравятся шаблоны?
это похоже на:
(1): — Ты зачем бьёшь молотком себе по пальцам?
(2): — Надеюсь у тебя не аллергии на молоток?
P>>>>4. вы слышали о code generation? С>>>может быть, был бы благодарен за ссылочку. P>>Код C++ можно генерировать программой/скриптом P>>1. Делаете описание схемы с помощью какого-нибудь подходящего формата, да хоть простого xml. P>>2. Парсите xml, естественно не вручную. P>>3. Генерируете код (необязательно весь. при этом до сих пор можно использовать рукописные шаблоны, так где это уместно) P>>А главное, результат будет на порядок более надёжный и на порядок более лёгкий в поддержке и использовании. Как следствие, намного более дешёвый в плане $$$$ С>Вам кажется, что так лучше и надёжней... Вероятно отпугивает не простой код, требующий квалификации для развития и поддержки... Но мы же не ищем лёгких путей!? ... Важны идеи!.. Прийдёт час и они окажутся востребованы... Всё новое рождается в муках... Методику генерации С++ кода из xml файлов с помощью xslt преобразования тоже применяем.
Вы понимаете, что сложные в поддержке техники адекватно использовать, когда они реально дают преимущество, которое трудно достичь более простыми способами.
Не один адекватный профессиональный программист не будет необоснованно использовать сложные техники, только ради использования, когда есть более элегантные, надёжные, и простые решения.
Тот же Александреску говорит, что он хочет упростить техники метапрограммирования, например добавить static if, чтобы заменить enable_if, неестественное наследование и т.п.
В вашем примере практического обоснования я не увидел. Быть может потому, что вы не ведите простых и элегантных решений. Вкус приходит с опытом.
Re[6]: Автоматическая генерация интерфейсов классов
Здравствуйте, Piko, Вы писали:
P>Здравствуйте, смит, Вы писали:
ЧВА>>>>>>Из пяти функций класса MessageDcd четыре функции относятся к интерфейсу доступа на чтение переменных класса. К ним еще необходимо добавить четыре функции доступа на запись переменных, которые реализуются по аналогии. P>>>>>
P>>>>>1. зачем здесь вообще getter'ы и setter'ы ? С>>... С>>>>Всё, теперь добавляем новое имя параметра, например new_mem_var, как элемент перечисления перед DCD_ID_NR, и определяем его характеристики в классе Parameter<DcdParameterIds, new_mem_var>. Никакого дублирования, компилятор сам добавит этот параметр в класс MessageSet. P>>>дублирование осталось, но уже меньше: нужно указывать первый (либо 0) и последний (либо следующий за последним) элементы. можно конечно и не указывать и обходить заведомо больший диапазон compile time, но это то ещё уродство. P>>>Также, нет никакой гарантии для пользователя что для всех элементов enum'а есть специализация parameter<>, что нет лишней специализации (например DcdEirp+3 ). В общем error-prone С>>Лишних специализаций не будет,
P>где гарантии того, что кто-нибудь не сделает лишнюю специализацию, для числа которого нет в enum, например "DcdEirp+3" ?
Так специализацию делать нельзя. Специализация -- это добавление новой информации, делаем её ручками и используем идентификаторы из перечисления. Поэтому эти идентификаторы имеют удобочитаемое для программиста имя, иначе писали бы программы так:
Компилятор "скушает" такой код, и программа может работать правильно. Но сам по себе код "DcdEirp+3" не безопасный и ничем не лучшеприведённого перечисления. "DcdEirp+3" допустимо только в том случае, если в исходном стандарте (ТЗ, IEEE 802.16) указаны относительные смещения, тогда мы следуем строго стандарту. И даже в этом случае специализировать надо DcdTTG, а не DcdEirp+3. Но это уже банальности.
С>>либо класс будет пустым без вопрощения в объект, либо будет регистрироваться класс по умолчанию, С>>шаблонами сделать это легко. P>как будет регистрироваться класс по-умолчанию, когда например программист забыл сделать специализацию parameter для DcdConfigChangeCount ?
: "...В языке С концепция перечислений выглядит незаконченной. В первоначальном варианте языка их не было. Перечисления ввели без всякой охоты в качестве уступки тем, кто настойчиво требовал более основательных символических констант, чем препроцессорные макросы без параметров..."
В данном случае приходится идти на компромисс: либо ручками добавляем каждый параметр и компилятор проверяет, все ли параметры специализированы, как у меня описано в статье. Либо делаем автоматическое добавление параметров с помощью рекурсии шаблонов, и по умолчанию вставляем заглушку. Во втором случае можно добавить препроцессорную директиву а-ля #warning "stub detected". #warning допустим, только (!) если заглушек немного, иначе вреда может быть больше чем пользы -- привыкание не обращать внимания на предупреждения. ( любые, указанные мной недостатки, могут быть использованы не в мою пользу )
P>А я ничего не говорил про время компиляции. я наоборот готов жертвовать временем компиляции ради надёжности
P>>>А главное вы не ответили чем это всё лучше простого аггрегирующего класса (с нормальной реализацией, а не как у вас с getters and setters). С>>Приведите, пожалуйста, пример Вашего кода, может я неправильно интерпретирую Ваши мысли.
P>Я же предлагаю вам подумать об более простом и элегантном способе: P>
"Я Вас умаляю...", присмотритесь, этот стакан наполовину наполнен... Класс Message<> является контейнером, у которого метод GetParametr<>() играет ту же роль, что и opertor[]() или метод at() у std::vector, выбор по индксу. И название метода GetParametr можно поменять на operator или at(), или добавить методы operator и at(). Как и vector, обладающий методами push_back(), begin() и т.д. класс Message имеет свои методы, которые не завязаны только на доступ к полям, нарпимер: SetPdu(), CreatePdu(), Reset() и т.п.
Я не против того, чтобы использовать простые структуры аналогично тому, как в ряде случаев мы используем массивы
Junior programmer не напишет класс std::vector с нуля (хотя, попадаются разные кадры), но использовать у себя в программе std::vector вполне ему по силам. Класс Message<> не простой в реализации, но пользоваться его методами не сложно. Не сложен и алгоритмом добавления параметров.
Следует заметить, что класс Message<> в методе выбора полей возвращает типизированные объекты, а не указатель или ссылку на базовый класс (как было бы в случае массива или вектора), что позволяет реализовать статическую (в режиме компиляции) диспетчеризацию обработки полей.
Другими столави, без контекста использования класса Message<> наша дискуссия будет не очень продуктивна, а в простых ситуациях с Вами трудно не согласиться.
Re[7]: Автоматическая генерация интерфейсов классов
Здравствуйте, смит, Вы писали:
С>Здравствуйте, Piko, Вы писали:
P>>Здравствуйте, смит, Вы писали:
С>Следует заметить, что класс Message<> в методе выбора полей возвращает типизированные объекты, а не указатель или ссылку на базовый класс (как было бы в случае массива или вектора), что позволяет реализовать статическую (в режиме компиляции) диспетчеризацию обработки полей. С>Другими словами, без контекста использования класса Message<> наша дискуссия будет не очень продуктивна, а в простых ситуациях с Вами трудно не согласиться.
Поправлю себя, правильно было бы написать возвращает не типизированные объекты, а объекты разных типов. Ну и в догонку написанному, перечисление enum в моём случае играет роль списка параметров, на основании его легко строить рекурсивные параметрические алгоритмы обработки полей, пробегание по списку, что позволяет в режиме компиляции (по индексу) автоматически регистрировать в классе новый параметр и все обработчики событий, с которыми этот параметр связан, только создав его определение. В случае простой структуры, приведённой Вами, при добавлении нового параметра необходимо будет регистрировать его обработчики в конструкторе вручную, искать по коду и в ручную добавлять его во все места, где требуется однотипная обработка или обработка списком, сложнее применить шаблонные функции. Здесь как раз касаемся деталей внутреннего устройства и контекста использования класса Message.
Re[6]: Автоматическая генерация интерфейсов классов
Здравствуйте, Kswapd, Вы писали:
P>>В вашем примере практического обоснования я не увидел. Быть может потому, что вы не ведите простых и элегантных решений. Вкус приходит с опытом.
K>Поддерживаю. Типичный наворот ради наворота. Для использования и поддержки надо затратить больше труда, чем если тупо вручную размножать классы.
Да кто ж с этим спорит. Разработка идёт поэтапно, от простого к сложному. Какой смысл городить сложные конструкции и generic алгоритмы в начале пути. К ним приходишь по мере развития проекта, композиции и обобщения разработанных структур и алгоритмов. Никто не спорит, что тупо накопи-пастить -- труда много не потребует. Первые реализации и были такими, как указывает Piko. Если обобщение позволяет кратно сократить код и добавить дополнительных проверок в compiled time не добавляя кода, упрощает масштабирование проекта, то смысл опять возвращаться к "мнимой простоте". Имеющий уши слышать, да услышит, имеющий глаза видеть — да увидит...
Re[8]: Автоматическая генерация интерфейсов классов
С>добавить дополнительных проверок в compiled time
Это именно то, что убивает C++ — из-за нечеловеческого синтаксиса и ограничений. Если возникла потребность в метапрограммировании и декларативности — пора менять инструмент.
Re[7]: Автоматическая генерация интерфейсов классов
Здравствуйте, смит, Вы писали:
P>>>>Также, нет никакой гарантии для пользователя что для всех элементов enum'а есть специализация parameter<>, что нет лишней специализации (например DcdEirp+3 ). В общем error-prone С>>>Лишних специализаций не будет, P>>где гарантии того, что кто-нибудь не сделает лишнюю специализацию, для числа которого нет в enum, например "DcdEirp+3" ? С>Так специализацию делать нельзя. Специализация -- это добавление новой информации, делаем её ручками и используем идентификаторы из перечисления. Поэтому эти идентификаторы имеют удобочитаемое для программиста имя, иначе писали бы программы так
:::: С>Компилятор "скушает" такой код, и программа может работать правильно. Но сам по себе код "DcdEirp+3" не безопасный и ничем не лучшеприведённого перечисления. "DcdEirp+3" допустимо только в том случае, если в исходном стандарте (ТЗ, IEEE 802.16) указаны относительные смещения, тогда мы следуем строго стандарту. И даже в этом случае специализировать надо DcdTTG, а не DcdEirp+3. Но это уже банальности.
вы меня не поняли.
вот есть у вас enum, в нём разные элементы и в конце DCD_ID_NR.
вот смотрит пользователь на этот enum и не знает есть ли специализация для DcdConfigChangeCount(то есть вообще сохраняется ли он), есть ли ошибочная специализация "DcdEirp+3", и т.п. Дублирование никуда не делось.
С>>>либо класс будет пустым без вопрощения в объект, либо будет регистрироваться класс по умолчанию, С>>>шаблонами сделать это легко. P>>как будет регистрироваться класс по-умолчанию, когда например программист забыл сделать специализацию parameter для DcdConfigChangeCount ? С>К сожалению перечисления сами по себе имеют ряд недостатков.
ну то есть вы сами понимаете что это не решение проблемы, и упорно продолжаете грызть кактус?
С>В данном случае приходится идти на компромисс: либо ручками добавляем каждый параметр и компилятор проверяет, все ли параметры специализированы, как у меня описано в статье. Либо делаем автоматическое добавление параметров с помощью рекурсии шаблонов, и по умолчанию вставляем заглушку.
ну то есть вы понимаете что оба варианта пахнут, и проигрывают X-Macros и Code Generation, но продолжаете их поддерживать?
Кстати, они проигрывают и аггрегирующему классу, хотя у него и те же проблемы, но он ведь намного легче и элегантей, и менее подвержен ошибкам.
P>>>>А главное вы не ответили чем это всё лучше простого аггрегирующего класса (с нормальной реализацией, а не как у вас с getters and setters). С>>>Приведите, пожалуйста, пример Вашего кода, может я неправильно интерпретирую Ваши мысли. P>>Я же предлагаю вам подумать об более простом и элегантном способе: P>>
А главное вы не ответили чем это всё лучше простого аггрегирующего класса (с нормальной реализацией, а не как у вас с getters and setters).
С>Junior programmer не напишет класс std::vector с нуля (хотя, попадаются разные кадры), но использовать у себя в программе std::vector вполне ему по силам. Класс Message<> не простой в реализации, но пользоваться его методами не сложно. Не сложен и алгоритмом добавления параметров.
так зачем его использовать, если есть намного более простые и надёжные варианты?
С>Следует заметить, что класс Message<> в методе выбора полей возвращает типизированные объекты, а не указатель или ссылку на базовый класс (как было бы в случае массива или вектора), что позволяет реализовать статическую (в режиме компиляции) диспетчеризацию обработки полей.
вы не поверите, простой аггрегирующий класс предоставляет простой доступ к типизированным объектам.
схема для обхода его полей может быть реализованны разными вариантами, например как
1. В boost::Serialization (обход полей runtime)
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & degrees;
ar & minutes;
ar & seconds;
}
2. либо в стиле tuple, c возможным compile-time обходом полей.
и замете, везде статическая типизация
С>Другими столави, без контекста использования класса Message<> наша дискуссия будет не очень продуктивна, а в простых ситуациях с Вами трудно не согласиться.
ну так вы ведь целую статью написали, а простого примера привести чем ваша реализация лучше простого агрегирующего класса не можете.