Комментарии 44
Мне кажется, что основная «эстетическая» проблема тут — отсутствие видимой декларации геттеров и сеттров. Это рвет шаблон.
А насчет макросов не негодуйте. Макросы — зло, их развивать никто не будет. Это даже хорошо, что нет перегрузки. Представьте какой зоопрак был бы.
А насчет макросов не негодуйте. Макросы — зло, их развивать никто не будет. Это даже хорошо, что нет перегрузки. Представьте какой зоопрак был бы.
+4
Думаю, можно было бы сделать синтаксис такой, чтоб smartfield принимал имена геттера и сеттера в качестве аргументов. Опять же если сделать так то если программист забудет написать один из методов то компилятор выведет что-то страшное, а так как сделано сейчас только то, что такой-то метод не реализован.
На счет макросов на самом деле склонен с вами согласиться, но мне кажется здесь они к месту. Можно было обойтись почти без всех макросов начинающих с "__", они все появились в процессе проб и ошибок и пока я придумывал код использовал такие блоки как детали конструктора.
На счет макросов на самом деле склонен с вами согласиться, но мне кажется здесь они к месту. Можно было обойтись почти без всех макросов начинающих с "__", они все появились в процессе проб и ошибок и пока я придумывал код использовал такие блоки как детали конструктора.
0
Было бы круто сделать объявления пропертей как в C#, но я не представляю как :)) Кстати, если вы завязаны на конкретный компайлер, то можно полазить по докам. Майкрософтовский С++, например, поддерживает проперти.
Ну вы же написали, что это просто этюд. Так что реализацию можно и не обсуждать глубоко.
Ну вы же написали, что это просто этюд. Так что реализацию можно и не обсуждать глубоко.
0
Я тоже сначала хотел сделать по образцу C#, но меня смутил тот факт, что в С++, в отличии от шарпа, принято разделять декларирование и реализацию.
Вообще я почти всегда использую студию, но кроссплатформенностью жертвовать не хотелось бы, поэтому надеюсь найти время и написать вторую версию для любого компилятора и с возможностью указания имен геттеров и сеттеров и может еще какими-нибудь плюшками.
Вообще я почти всегда использую студию, но кроссплатформенностью жертвовать не хотелось бы, поэтому надеюсь найти время и написать вторую версию для любого компилятора и с возможностью указания имен геттеров и сеттеров и может еще какими-нибудь плюшками.
0
Это не сильно распрострено, но не является чем-то чуждым для С++. Так поступают с инлайнами в классах или с шаблонами.
Я вот это имел в виду:
Такое на С++ не напишешь :)
Я вот это имел в виду:
class TimePeriod
{
private double seconds;
public double Hours
{
get { return seconds / 3600; }
set { seconds = value * 3600; }
}
}
Такое на С++ не напишешь :)
0
Нуууу… Может и не напишешь. Сходу я придумал что-то похожее только для доступа по имени из ран-тайма. Заведем в базовом классе (а я считаю, что наследование от базового класса это не плохо) виртуальный метод void _fieldsection(), который будем вызывать из конструктора. Заведем макрос #define fieldsection _fieldsection(). Теперь мы в классе можем написать так:
здесь field — макрос, который разворачивается в вызов метода добавление поля в класс, а get и set разворачиваются в лямбда функции, которые сохраняются соответственно текущему полю. Не могу только придумать, как сделать обращение через. или ->.
class Foo
{
fieldsection
{
field(int, a)
{
get {...}
set {...}
}
}
...
}
здесь field — макрос, который разворачивается в вызов метода добавление поля в класс, а get и set разворачиваются в лямбда функции, которые сохраняются соответственно текущему полю. Не могу только придумать, как сделать обращение через. или ->.
0
А что, мне нравится.
0
В принципе, если мне удастся запилить что-то вроде рефлексии — сделать действительно красиво как в шарпе будет не сложно.
Подскажите, может я торможу, но нельзя ли сделать конкатизацию при редекларировании дефайна предыдущего значения с новым:
#define MACRO мясо
#define MACRO есть_##MACRO
Надо чтоб получилось «есть_мясо», а генерится «есть_MACRO»
Подскажите, может я торможу, но нельзя ли сделать конкатизацию при редекларировании дефайна предыдущего значения с новым:
#define MACRO мясо
#define MACRO есть_##MACRO
Надо чтоб получилось «есть_мясо», а генерится «есть_MACRO»
0
Какая-то жуткая смесь Си, C++ и С++0x с регулярным эксплуатированием багов компилятора студии. Гигантские макросы, которые разворачиваются в шаблоны, которые инстанциируются для классов, которые в свою очередь сгенерированы препроцессором. Мечта для любителей отладки.
А причина появления статьи просто гениальна: «в C++ нет средства описания полей класса с контролируемым доступом, как например property в C#». Конец объяснений (к слову, в прошлой статье то же самое). Опять же, полный игнор комментариев к предыдущей статье. Извините, но это совсем не fun.
А причина появления статьи просто гениальна: «в C++ нет средства описания полей класса с контролируемым доступом, как например property в C#». Конец объяснений (к слову, в прошлой статье то же самое). Опять же, полный игнор комментариев к предыдущей статье. Извините, но это совсем не fun.
+5
Понятное дело, что никто не собирается это использовать в реальном проекте. Что плохого в том, чтобы в свое удовольствие написать что-то такое жуткое, но интересное? Кому-то это просто нравится, вот и все.
+2
Плохое в том, что перед написанием кода неплохо бы задаться реальной практической целью, с которой пишется код. Люди видят, что в языках есть интроспекция и сразу накручивают макросы добавления метаданных к классу «чтобы просто были». Люди видят, что в языках есть рефлексия и сразу на каждое поле данных класса приделывают класс с теми самыми метаданными. Зачем нужна интроспекция и рефлексия никого не волнует.
А ведь можно было задаться целью написать систему сериализации/десериализации классов, в которых поля определены как «field(float, f);». Или приделать систему динамического добавления полей. В любом случае нужно задаться реальной целью до начала написания кода.
А ведь можно было задаться целью написать систему сериализации/десериализации классов, в которых поля определены как «field(float, f);». Или приделать систему динамического добавления полей. В любом случае нужно задаться реальной целью до начала написания кода.
0
Искусство ради искусства.
0
Интересно получилось. Как автор предыдущей статьи скажу, что у вас получилось гораздо красивее с точки зрения синтаксиса. Я, кстати, на той статье не остановился и немного развил идею . Красивее не стало, зато теперь намного безопаснее. К ваше реализации есть пара претензий:
1) Использование чисто майкрософтовских «фич», которые нарушают кроссплатформенность. В студии и так есть свои проперти.
3) Неявное задание сеттеров и геттеров, которое ещё и обязывает по-вашему называть методы.
2) Не смог до конца разобраться, но как создать readonly свойство?
У меня сейчас бродят идеи реализации на основе новшеств C++11. Лямбды вместе с std::function помогут сделать обьяления методов доступа красивее, а возможность вызывать конструкторы друг из друга — выделить инициализацию свойств в отдельный конструктор.
1) Использование чисто майкрософтовских «фич», которые нарушают кроссплатформенность. В студии и так есть свои проперти.
3) Неявное задание сеттеров и геттеров, которое ещё и обязывает по-вашему называть методы.
2) Не смог до конца разобраться, но как создать readonly свойство?
У меня сейчас бродят идеи реализации на основе новшеств C++11. Лямбды вместе с std::function помогут сделать обьяления методов доступа красивее, а возможность вызывать конструкторы друг из друга — выделить инициализацию свойств в отдельный конструктор.
0
1) Уже взял на заметку и собираюсь с этим бороться
3) Я думал это фича, но судя по комментариям следует дать возможность программисту самостоятельно описывать методы get и set.
2) Не задумывался об этом, но smartfield + пустой сеттер (или который например кидает эксепшн)
На счет развития идеи — тоже взял на заметку, позже разберусь.
И на счет использования нового стандарта — эта идея мне действительно кажется хорошей и может быть получится сделать действительно пригодную для использования реализацию.
3) Я думал это фича, но судя по комментариям следует дать возможность программисту самостоятельно описывать методы get и set.
2) Не задумывался об этом, но smartfield + пустой сеттер (или который например кидает эксепшн)
На счет развития идеи — тоже взял на заметку, позже разберусь.
И на счет использования нового стандарта — эта идея мне действительно кажется хорошей и может быть получится сделать действительно пригодную для использования реализацию.
0
Зачем!?
+3
Я очень негодую отсутствую в препроцессоре возможности перегрузки макросов хотя бы по числу аргументов
На сколько я знаю, с помощью boost preprocessor'а можно указать параметр с любым количеством параметров или что-то похожее. Перегрузить конечно макрос нельзя, но можно вроде обойтись листом параметров. Вот небольшая тема как реализовать подобное на gcc без boost'а.
0
>«Например поле типа int с именем «x». Нас вполне устроит такая запись: field(int,x);»
«отучаемся говорить за всех»©FIDO
меня устроит запись get_x() и set_x(v)
«отучаемся говорить за всех»©FIDO
меня устроит запись get_x() и set_x(v)
+1
То есть, мы забили на все плюшки статической типизации, и сделали странный, кривой и неустойчивый динамический сеттер/геттер. А в чем профит?
+4
По-моему, достаточно просто заполнить map<string, T>, и добавить к этому T &operator()(string). А в конструкторе заполнить мапу известными полями. Тогда такая запись:
obj("fieldName") = value; // имеет место быть
0
Ссылку на что вернет ваш оператор, если поля не существует?
0
По идее исключение можно вызвать. А можно просто T()
0
Т.е. малейшая опечатка и узнаете об этом только во время выполнения программы (исключение). Либо вообще не узнаете, а будете час судорожно искать почему у вас не работает приложение (в случае T()).
Такие вещи должны во время компиляции всплывать.
Я уж не говорю о том, что никакие вижуал ассисты и интеллисенсы не смогут вам подсказать имя поля.
Такие вещи должны во время компиляции всплывать.
Я уж не говорю о том, что никакие вижуал ассисты и интеллисенсы не смогут вам подсказать имя поля.
0
Чем больше я смотрю на C++, тем больше нравится мне Ruby © перефразировал классика
class Foo
attr_accessor :x
end
class Foo
attr_accessor :x
end
-4
Ну вы хотя бы из любви к рациональности заюзали в базовом классе хеш-таблицу вместо вектора с линейным поиском и сравнением строк на каждой итерации.
К слову, нечто отдаленно похожее реализовано в .NET Framework в классе DependencyObject. Но там цель всего этого заключалась в том, что бы можно было описывать граф распространения значений свойств набора объектов, как набор других объектов, строить цепочки связанных свойств. Проще говоря, для организации Data Binding'а.
К слову, нечто отдаленно похожее реализовано в .NET Framework в классе DependencyObject. Но там цель всего этого заключалась в том, что бы можно было описывать граф распространения значений свойств набора объектов, как набор других объектов, строить цепочки связанных свойств. Проще говоря, для организации Data Binding'а.
0
Касаемо перегрузки макросов, есть такая штука как variadic macro.
Полного решения проблемы это не даёт, но можно через этот variadic macro сделать вызов разных перегруженных методов. Я это использовал в своей библиотеке журналирования для Qt, о которой пока не успел написать на Хабре.
Выглядит это примерно так:
В вызываемом коде:
Проверка типов на этапе компиляции работает. В принципе, никто не мешает вместо пачки статических функций сделать #define на шаблонизированную функцию.
Полного решения проблемы это не даёт, но можно через этот variadic macro сделать вызов разных перегруженных методов. Я это использовал в своей библиотеке журналирования для Qt, о которой пока не успел написать на Хабре.
Выглядит это примерно так:
#define LOG_DEBUG(...) Logger::write(Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
...
class Logger
{
public:
...
static void write(LogLevel logLevel, const char* file, int line, const char* function,
const QString& message);
static void write(LogLevel logLevel, const char* file, int line, const char* function,
const char* message);
static QDebug write(LogLevel logLevel, const char* file, int line, const char* function);
...
}
В вызываемом коде:
LOG_DEBUG("Test1");
LOG_DEBUG(tr("Test2")); // QObject::tr() возвращает QString
LOG_DEBUG() << "Test 3:" << testValue; // У объекта QDebug есть перегруженный operator<<
Проверка типов на этапе компиляции работает. В принципе, никто не мешает вместо пачки статических функций сделать #define на шаблонизированную функцию.
0
Очередной костыль для С++. Ради чуть лучшей читаемости наворотили чёрти-чего и сбоку бантик. Зачем? С++ прекрасен и без этих конструкций.
Может пора пересесть на C#? Или на Delphi? Там это лет 15 назад уже было.
PS: Впрочем, как академические упражнения в написании макросов и шаблонов, довольно занимательно.
Может пора пересесть на C#? Или на Delphi? Там это лет 15 назад уже было.
PS: Впрочем, как академические упражнения в написании макросов и шаблонов, довольно занимательно.
+1
У майкрософта есть своя версия
0
В одном из своих проектов использую такой вариант:
Тоже не бог весть что, но позволяет достигнуть желаемого эффекта («описания полей класса с контролируемым доступом»).
class FullStrategyMapScene : public QGraphicsScene
{
Q_OBJECT;
public:
// Инициализируем свойства
FullStrategyMapScene() : properties(this) {;}
~FullStrategyMapScene();
// Объявляем свойства
PROPERTIES(FullStrategyMapScene,
// Простое свойство
PROPERTY(QSize, CellSize)
// Простое свойство с инициализацией
PROPERTY_I(Unit const*, CurrentUnit, NULL)
// Свойство с геттером и сеттером
RW_PROPERTY(QPoint, CursorPos, GetCursorPos, SetCursorPos)
// Свойство с сеттером
WO_PROPERTY(IPlanet const*, Planet, SetPlanet)
RO_PROPERTY(ISurfaceMap const*, SurfaceMap, GetSurfaceMap)
);
private:
void SetPlanet(IPlanet const* planet);
QPoint const& GetCursorPos() const;
void SetCursorPos(QPoint const& pos);
ISurfaceMap const* GetSurfaceMap() const;
};
Тоже не бог весть что, но позволяет достигнуть желаемого эффекта («описания полей класса с контролируемым доступом»).
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Поля класса доступные по имени с setter и getter в C++