No C ++, os inicializadores do estilo C foram substituídos por construtores que, durante o tempo de compilação, podem garantir que apenas as inicializações válidas sejam realizadas (ou seja, após a inicialização, os membros do objeto são consistentes).
É uma boa prática, mas às vezes uma pré-inicialização é útil, como no seu exemplo. OOP resolve isso por classes abstratas ou padrões de design criacionais .
Na minha opinião, o uso dessa maneira segura reduz a simplicidade e, às vezes, a troca de segurança pode ser muito cara, pois o código simples não precisa de design sofisticado para manter a manutenção.
Como solução alternativa, sugiro definir macros usando lambdas para simplificar a inicialização para se parecer quase com o estilo 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
A macro ADDRESS se expande para
[] { address _={}; /* definition... */ ; return _; }()
que cria e chama o lambda. Os parâmetros de macro também são separados por vírgula; portanto, você precisa colocar o inicializador entre colchetes e chamar como
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
Você também pode escrever inicializador de macro generalizado
#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
mas a chamada é um pouco menos bonita
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
no entanto, você pode definir a macro ADDRESS usando a macro INIT geral facilmente
#define ADDRESS(x) INIT(address,x)