sirve que para lenguaje funciones estructuras estructura ejercicios con comandos anidadas c++ struct initialization

que - Cómoda inicialización de estructuras C++



funciones con estructuras en c (10)

Estoy tratando de encontrar una forma conveniente de inicializar estructuras C ++ ''pod''. Ahora, considere la siguiente estructura:

struct FooBar { int foo; float bar; }; // just to make all examples work in C and C++: typedef struct FooBar FooBar;

Si quiero inicializar convenientemente esto en C (!), Simplemente podría escribir:

/* A */ FooBar fb = { .foo = 12, .bar = 3.4 }; // illegal C++, legal C

Tenga en cuenta que quiero evitar explícitamente la siguiente notación, porque me da la impresión de que me rompe el cuello si cambio algo en la estructura en el futuro:

/* B */ FooBar fb = { 12, 3.4 }; // legal C++, legal C, bad style?

Para lograr lo mismo (o al menos similar) en C ++ como en el /* A */ ejemplo, tendría que implementar un constructor idiota:

FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar) {} // -> /* C */ FooBar fb(12, 3.4);

Lo cual es bueno para hervir agua, pero no es adecuado para personas perezosas (la pereza es algo bueno, ¿no?). Además, es casi tan malo como el /* B */ example, ya que no establece explícitamente qué valor va a cada miembro.

Entonces, ¿mi pregunta es básicamente cómo puedo lograr algo similar a /* A */ o mejor en C ++? Alternativamente, estaría bien con una explicación de por qué no quisiera hacer esto (es decir, por qué mi paradigma mental es malo).

EDITAR

Por conveniente , quiero decir también mantenible y no redundante .


¿Qué hay de esta sintaxis?

typedef struct { int a; short b; } ABCD; ABCD abc = { abc.a = 5, abc.b = 7 };

Recién probado en Microsoft Visual C ++ 2015 y en g ++ 6.0.2. Trabajando bien
También puede crear una macro específica si desea evitar la duplicación del nombre de la variable.


Como el style A no está permitido en C ++ y no quieres el style B , ¿qué hay de usar el style BX ?

FooBar fb = { /*.foo=*/ 12, /*.bar=*/ 3.4 }; // :)

Al menos ayuda en cierta medida.


Extraiga los contantes en funciones que los describan (refactorización básica):

FooBar fb = { foo(), bar() };

Sé que ese estilo es muy parecido al que no quería usar, pero permite un reemplazo más fácil de los valores constantes y también los explica (por lo tanto, no necesita editar comentarios), si alguna vez cambian eso.

Otra cosa que podrías hacer (ya que eres flojo) es hacer el constructor en línea, para que no tengas que escribir tanto (eliminando "Foobar ::" y el tiempo dedicado a cambiar entre el archivo h y cpp):

struct FooBar { FooBar(int f, float b) : foo(f), bar(b) {} int foo; float bar; };


La forma /* B */ está bien en C ++, también C ++ 0x ampliará la sintaxis, por lo que también es útil para contenedores C ++. No entiendo por qué lo llamas mal estilo?

Si desea indicar parámetros con nombres, puede usar la biblioteca de parámetros de impulso , pero puede confundir a alguien que no esté familiarizado con ellos.

Reordenar los miembros de la estructura es como reordenar los parámetros de la función, tal refactorización puede causar problemas si no lo hace con mucho cuidado.


Muchos frontales de C ++ de compiladores (incluyendo GCC y clang) entienden la sintaxis del inicializador C. Si puedes, simplemente usa ese método.


Opción D:

FooBar FooBarMake(int foo, float bar)

Legal C, legal C ++. Fácilmente optimizable para POD. Por supuesto, no hay argumentos con nombre, pero esto es como todos los C ++. Si desea argumentos con nombre, Objective C debería ser una mejor opción.

Opción E:

FooBar fb; memset(&fb, 0, sizeof(FooBar)); fb.foo = 4; fb.bar = 15.5f;

Legal C, legal C ++. Argumentos con nombre


Otra forma en C ++ es

struct Point { private: int x; int y; public: Point& setX(int xIn) { x = Xin; return *this;} Point& setY(int yIn) { y = Yin; return *this;} } Point pt; pt.setX(20).setY(20);


Puedes usar un lambda:

const FooBar fb = [&] { FooBar fb; fb.foo = 12; fb.bar = 3.4; return fb; }();

Se puede encontrar más información sobre este modismo en el blog de Herb Sutter .


Sé que esta pregunta es antigua, pero hay una manera de resolver esto hasta que C ++ 20 finalmente traiga esta característica de C a C ++. Lo que puede hacer para resolver esto es usar las macros de preprocesador con static_asserts para verificar que su inicialización sea válida. (Sé que las macros son generalmente malas, pero aquí no veo otra forma). Vea el siguiente código de ejemplo:

#define INVALID_STRUCT_ERROR "Instantiation of struct failed: Type, order or number of attributes is wrong." #define CREATE_STRUCT_1(type, identifier, m_1, p_1) / { p_1 };/ static_assert(offsetof(type, m_1) == 0, INVALID_STRUCT_ERROR);/ #define CREATE_STRUCT_2(type, identifier, m_1, p_1, m_2, p_2) / { p_1, p_2 };/ static_assert(offsetof(type, m_1) == 0, INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_2) >= sizeof(identifier.m_1), INVALID_STRUCT_ERROR);/ #define CREATE_STRUCT_3(type, identifier, m_1, p_1, m_2, p_2, m_3, p_3) / { p_1, p_2, p_3 };/ static_assert(offsetof(type, m_1) == 0, INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_2) >= sizeof(identifier.m_1), INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_3) >= (offsetof(type, m_2) + sizeof(identifier.m_2)), INVALID_STRUCT_ERROR);/ #define CREATE_STRUCT_4(type, identifier, m_1, p_1, m_2, p_2, m_3, p_3, m_4, p_4) / { p_1, p_2, p_3, p_4 };/ static_assert(offsetof(type, m_1) == 0, INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_2) >= sizeof(identifier.m_1), INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_3) >= (offsetof(type, m_2) + sizeof(identifier.m_2)), INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_4) >= (offsetof(type, m_3) + sizeof(identifier.m_3)), INVALID_STRUCT_ERROR);/ // Create more macros for structs with more attributes...

Entonces, cuando tienes una estructura con atributos const, puedes hacer esto:

struct MyStruct { const int attr1; const float attr2; const double attr3; }; const MyStruct test = CREATE_STRUCT_3(MyStruct, test, attr1, 1, attr2, 2.f, attr3, 3.);

Es un poco incómodo, porque necesita macros para cada número posible de atributos y necesita repetir el tipo y nombre de su instancia en la macro llamada. Además, no puede usar la macro en una declaración de devolución, porque las afirmaciones vienen después de la inicialización.

Pero resuelve tu problema: cuando cambias la estructura, la llamada fallará en tiempo de compilación.

Si usa C ++ 17, incluso puede hacer que estas macros sean más estrictas forzando los mismos tipos, por ejemplo:

#define CREATE_STRUCT_3(type, identifier, m_1, p_1, m_2, p_2, m_3, p_3) / { p_1, p_2, p_3 };/ static_assert(offsetof(type, m_1) == 0, INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_2) >= sizeof(identifier.m_1), INVALID_STRUCT_ERROR);/ static_assert(offsetof(type, m_3) >= (offsetof(type, m_2) + sizeof(identifier.m_2)), INVALID_STRUCT_ERROR);/ static_assert(typeid(p_1) == typeid(identifier.m_1), INVALID_STRUCT_ERROR);/ static_assert(typeid(p_2) == typeid(identifier.m_2), INVALID_STRUCT_ERROR);/ static_assert(typeid(p_3) == typeid(identifier.m_3), INVALID_STRUCT_ERROR);/


Tu pregunta es algo difícil porque incluso la función:

static FooBar MakeFooBar(int foo, float bar);

puede ser llamado como:

FooBar fb = MakeFooBar(3.4, 5);

debido a las reglas de promoción y conversión para los tipos numéricos incorporados. (C nunca se ha escrito con mucha fuerza)

En C ++, lo que desea es alcanzable, aunque con la ayuda de plantillas y aserciones estáticas:

template <typename Integer, typename Real> FooBar MakeFooBar(Integer foo, Real bar) { static_assert(std::is_same<Integer, int>::value, "foo should be of type int"); static_assert(std::is_same<Real, float>::value, "bar should be of type float"); return { foo, bar }; }

En C, puedes nombrar los parámetros, pero nunca llegarás más lejos.

Por otro lado, si todo lo que quieres son parámetros nombrados, entonces escribes un montón de código engorroso:

struct FooBarMaker { FooBarMaker(int f): _f(f) {} FooBar Bar(float b) const { return FooBar(_f, b); } int _f; }; static FooBarMaker Foo(int f) { return FooBarMaker(f); } // Usage FooBar fb = Foo(5).Bar(3.4);

Y puede utilizar la protección de promoción tipo si lo desea.