In C ++ gli inizializzatori in stile C sono stati sostituiti da costruttori che in fase di compilazione possono garantire che vengano eseguite solo inizializzazioni valide (cioè dopo l'inizializzazione i membri dell'oggetto sono coerenti).
È una buona pratica, ma a volte una pre-inizializzazione è utile, come nel tuo esempio. OOP risolve questo problema con classi astratte o modelli di progettazione creazionale .
A mio avviso, l'utilizzo di questo modo sicuro uccide la semplicità e talvolta il compromesso di sicurezza potrebbe essere troppo costoso, poiché un semplice codice non ha bisogno di un design sofisticato per rimanere sostenibile.
Come soluzione alternativa, suggerisco di definire le macro usando lambdas per semplificare l'inizializzazione in modo che assomigli quasi allo stile 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
La macro ADDRESS si espande in
[] { address _={}; /* definition... */ ; return _; }()
che crea e chiama la lambda. Anche i parametri macro sono separati da virgola, quindi è necessario mettere l'inizializzatore tra parentesi e chiamare like
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
È inoltre possibile scrivere un inizializzatore di macro generalizzato
#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
ma poi la chiamata è leggermente meno bella
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
tuttavia è possibile definire facilmente la macro ADDRESS utilizzando la macro INIT generale
#define ADDRESS(x) INIT(address,x)