estructuras - Inicialización de la estructura de C++
estructuras en c++ pdf (15)
¿Es posible inicializar estructuras en C ++ como se indica a continuación?
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
Los enlaces here y here mencionan que es posible usar este estilo solo en C. Si es así, ¿por qué no es posible en C ++? ¿Existe alguna razón técnica subyacente por la que no se implementa en C ++ o es una mala práctica usar este estilo? Me gusta usar esta forma de inicializar porque mi estructura es grande y este estilo me da una legibilidad clara de qué valor se asigna a cada miembro.
Por favor, comparta conmigo si hay otras formas a través de las cuales podamos lograr la misma legibilidad.
He referido los siguientes enlaces antes de publicar esta pregunta.
Como otros han mencionado, esto se designa como inicializador.
Esta característica es parte de C++20
Después de que here resultó en un resultado no satisfactorio (porque C ++ no implementa el inicio basado en etiquetas para las estructuras), tomé el truco que encontré aquí: ¿Los miembros de una estructura C ++ están inicializados a 0 de forma predeterminada?
Para ti equivaldría a hacer eso:
address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";
Este es ciertamente el más cercano a lo que originalmente quería (cero todos los campos excepto aquellos que desea inicializar).
En C ++, los inicializadores de estilo C fueron reemplazados por constructores que, por tiempo de compilación, pueden garantizar que solo se realicen inicializaciones válidas (es decir, después de la inicialización, los miembros del objeto son consistentes).
Es una buena práctica, pero a veces es útil una preinicialización, como en su ejemplo. La POO resuelve esto mediante clases abstractas o patrones de diseño creativo .
En mi opinión, el uso de esta forma segura mata la simplicidad y, a veces, el compromiso de seguridad puede ser demasiado costoso, ya que el código simple no necesita un diseño sofisticado para mantenerse.
Como solución alternativa, sugiero definir macros usando lambdas para simplificar la inicialización para que se parezca casi al 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
La macro DIRECCIÓN se expande a
[] { address _={}; /* definition... */ ; return _; }()
Que crea y llama a la lambda. Los parámetros de macro también están separados por comas, por lo que debe poner el inicializador entre paréntesis y llamar como
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
También podrías escribir inicializador de macro generalizado.
#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
Pero entonces la llamada es un poco menos bella.
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
sin embargo, puede definir la macro DIRECCIÓN utilizando la macro INIT general fácilmente
#define ADDRESS(x) INIT(address,x)
Encontré esta forma de hacerlo para variables globales, que no requiere modificar la definición de estructura original:
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
luego declare la variable de un nuevo tipo heredado del tipo de estructura original y use el constructor para la inicialización de los campos:
struct temp_address : address { temp_address() {
city = "Hamilton";
prov = "Ontario";
} } temp_address;
Aunque no es tan elegante como el estilo C ...
Para la variable local también debería ser posible, pero debe verificar si un memset adicional (esto, 0, sizeof (* this)) sería necesario entonces ...
(Tenga en cuenta que ''temp_address'' es una variable de tipo ''temp_address'', sin embargo, este nuevo tipo se hereda de ''address'' y se puede usar en cualquier lugar donde se espere ''address'', por lo que está bien).
Es posible, pero solo si la estructura que está inicializando es una estructura POD (datos antiguos). No puede contener ningún método, constructor, o incluso valores por defecto.
Esta característica se llama inicializadores designados . Es una adición al estándar C99. Sin embargo, esta característica se dejó fuera del C ++ 11. De acuerdo con The C ++ Programming Language, 4ª edición, Sección 44.3.3.2 (Características de C no adoptadas por C ++):
Algunas adiciones a C99 (en comparación con C89) no fueron adoptadas deliberadamente en C ++:
[1] Arreglos de longitud variable (VLA); utilizar vector o alguna forma de matriz dinámica
[2] Inicializadores designados; usar constructores
La gramática C99 tiene los inicializadores designados [Ver ISO / IEC 9899: 2011, borrador del Comité N1570 - 12 de abril de 2011]
6.7.9 Inicialización
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designation_opt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
Por otro lado, el C ++ 11 no tiene los inicializadores designados [Ver ISO / IEC 14882: 2011, borrador del Comité N3690 - 15 de mayo de 2013]
8.5 Inicializadores
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
initializer-list:
initializer-clause ...opt
initializer-list , initializer-clause ...opt
braced-init-list:
{ initializer-list ,opt }
{ }
Para lograr el mismo efecto, use constructores o listas de inicializadores:
Hoy enfrenté un problema similar, donde tengo una estructura que quiero llenar con datos de prueba que se pasarán como argumentos a una función que estoy probando. Quería tener un vector de estas estructuras y estaba buscando un método de una sola línea para inicializar cada estructura.
Terminé yendo con una función constructora en la estructura, que creo que también fue sugerida en algunas respuestas a su pregunta.
Probablemente sea una mala práctica tener los argumentos para que el constructor tenga los mismos nombres que las variables miembro públicas, lo que requiere el uso de this
puntero. Alguien puede sugerir una edición si hay una mejor manera.
typedef struct testdatum_s {
public:
std::string argument1;
std::string argument2;
std::string argument3;
std::string argument4;
int count;
testdatum_s (
std::string argument1,
std::string argument2,
std::string argument3,
std::string argument4,
int count)
{
this->rotation = argument1;
this->tstamp = argument2;
this->auth = argument3;
this->answer = argument4;
this->count = count;
}
} testdatum;
Que utilicé en mi función de prueba para llamar a la función que se está probando con varios argumentos como este:
std::vector<testdatum> testdata;
testdata.push_back(testdatum("val11", "val12", "val13", "val14", 5));
testdata.push_back(testdatum("val21", "val22", "val23", "val24", 1));
testdata.push_back(testdatum("val31", "val32", "val33", "val34", 7));
for (std::vector<testdatum>::iterator i = testdata.begin(); i != testdata.end(); ++i) {
function_in_test(i->argument1, i->argument2, i->argument3, i->argument4m i->count);
}
Incluso puede empaquetar la solución de Gui13 en una sola declaración de inicialización:
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);
Descargo de responsabilidad: no recomiendo este estilo
Los identificadores de campo son de hecho la sintaxis del inicializador C. En C ++ solo da los valores en el orden correcto sin los nombres de los campos. Desafortunadamente, esto significa que debe proporcionarlos a todos (en realidad, puede omitir los campos finales de valor cero y el resultado será el mismo):
address temp_address = { 0, 0, "Hamilton", "Ontario", 0 };
No está implementado en C ++. (también, char*
cuerdas? espero que no).
Por lo general, si tiene tantos parámetros es un olor de código bastante serio. Pero en su lugar, ¿por qué no simplemente inicializar con valor la estructura y luego asignar a cada miembro?
Puede que me esté perdiendo algo aquí, por qué no:
#include <cstdio>
struct Group {
int x;
int y;
const char* s;
};
int main()
{
Group group {
.x = 1,
.y = 2,
.s = "Hello it works"
};
printf("%d, %d, %s", group.x, group.y, group.s);
}
Sé que esta pregunta es bastante antigua, pero encontré otra forma de inicializar, usando constexpr y curry:
struct mp_struct_t {
public:
constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {}
constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {}
constexpr mp_struct_t another_member(int member) { return {member1, member, member2}; }
constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; }
int member1, member2, member3;
};
static mp_struct_t a_struct = mp_struct_t{1}
.another_member(2)
.yet_another_one(3);
Este método también funciona para variables estáticas globales e incluso constexpr. La única desventaja es la mala capacidad de mantenimiento: cada vez que se debe inicializar otro miembro con este método, se deben cambiar todos los métodos de inicialización de miembros.
Si desea aclarar cuál es el valor de cada inicializador, simplemente divídalo en varias líneas, con un comentario en cada una:
address temp_addres = {
0, // street_no
nullptr, // street_name
"Hamilton", // city
"Ontario", // prov
nullptr, // postal_code
};
Solo puedes inicializar via ctor:
struct address {
address() : city("Hamilton"), prov("Ontario") {}
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
puede usar extern "C" para compilar el código c en C ++. En su caso puede utilizar el siguiente código.
extern "C" {
//write your C code which you want to compile in C++
struct address {
int street_no;
char *street_name;`enter code here`
char *city;
char *prov;
char *postal_code;
};
address temp_address ={ .city = "Hamilton", .prov = "Ontario" };
}