В C ++ инициализаторы в стиле C были заменены конструкторами, которые во время компиляции могут обеспечить выполнение только допустимых инициализаций (т.е. после инициализации члены объекта являются согласованными).
Это хорошая практика, но иногда удобна предварительная инициализация, как в вашем примере. ООП решает это с помощью абстрактных классов или шаблонов дизайна .
На мой взгляд, использование этого безопасного способа убивает простоту, и иногда компромисс в безопасности может быть слишком дорогим, поскольку простой код не нуждается в сложном дизайне, чтобы оставаться обслуживаемым.
В качестве альтернативного решения я предлагаю определить макросы с использованием лямбда-выражений, чтобы упростить инициализацию, чтобы она выглядела почти как стиль C:
struct address {
int street_no;
const char *street_name;
const char *city;
const char *prov;
const char *postal_code;
};
#define ADDRESS_OPEN [] { address _={};
#define ADDRESS_CLOSE ; return _; }()
#define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE
Макрос ADDRESS расширяется до
[] { address _={}; /* definition... */ ; return _; }()
который создает и вызывает лямбду. Параметры макроса также разделяются запятыми, поэтому вам нужно заключить инициализатор в скобки и вызвать
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
Вы также можете написать обобщенный инициализатор макроса
#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
но тогда звонок чуть менее красив
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
однако вы можете легко определить макрос ADDRESS, используя общий макрос INIT
#define ADDRESS(x) INIT(address,x)