Edited
In the comments:
I work with a function that returns the value of a field and every time it is invoked it returns the value of the next field in that record
As I understand it, the function you speak of works sequentially, in which case you can settle a solution (which is not simple either). We will start by saving the elements that we want to assign in the structure itself:
struct Ejemplo{
char c;
short s;
int i;
float f;
double d;
// Coleccion de elementos asignables de la estructura
static constexpr auto data = std::make_tuple(
&Ejemplo::c,
&Ejemplo::s,
&Ejemplo::i,
&Ejemplo::f,
&Ejemplo::d
);
};
Then we use a recursive function that goes element to element of the collection and calls a function to assign them value:
template <std::size_t ELEMENTOS>
void asigna(Ejemplo &ejemplo)
{
constexpr auto data_size = std::tuple_size<decltype(Ejemplo::data)>::value;
static_assert(ELEMENTOS <= data_size);
auto miembro = std::get<data_size - ELEMENTOS>(Ejemplo::data);
ejemplo.*miembro = funcion_que_me_devuelve_el_valor_de_un_campo();
asigna<ELEMENTOS - 1>(ejemplo);
}
// Funcion vacia que rompe la recursion
template <>
void asigna<0u>(Ejemplo &) {}
With this approach you can assign the values of Ejemplo
sequentially with this call:
Ejemplo var;
asigna<5u>(var);
If you have the possibility to compile in C ++ 17 the solution is slightly more interesting:
template <std::size_t ELEMENTOS, typename FUNCION>
void asigna(Ejemplo &ejemplo, [[maybe_unused]] FUNCION funcion)
{
if constexpr (ELEMENTOS)
{
constexpr auto data_size = std::tuple_size<decltype(Ejemplo::data)>::value;
static_assert(ELEMENTOS <= data_size);
auto miembro = std::get<data_size - ELEMENTOS>(Ejemplo::data);
ejemplo.*miembro = funcion();
asigna<ELEMENTOS - 1>(ejemplo, funcion);
}
}
You save the empty function to break the recursion by using if constexpr
and we can add the function that returns the value of the next field as a parameter ... which we could not before because the functions templates can not be specialized, with this new approach in C ++ 17 the call would be:
Ejemplo var;
asigna<5u>(var, funcion_que_me_devuelve_el_valor_de_un_campo);
You can see the code [working here] .
Original reply
I'm interested in doing something like this:
for(int i=0; i<N; i++){
var.algo = i;
}
This is possible to do (but it's not practical) using member pointers:
struct Ejemplo{
int a;
int b;
int c;
int d;
int z;
using puntero_a_miembro = int Ejemplo::*;
constexpr static puntero_a_miembro datos[5]{
&Ejemplo::a,
&Ejemplo::b,
&Ejemplo::c,
&Ejemplo::d,
&Ejemplo::z
};
};
We save in Ejemplo::datos
1 the position in Ejemplo
of each of its members and then assign them using a loop:
Ejemplo var;
for (int i = 0; i < 5; ++i){
var.*Ejemplo::datos[i] = i;
}
Not practical because:
- The syntax is confusing.
- Requires manually maintaining the
Ejemplo::datos
fix: If new data is added to the structure, we need to add them to the array.
- Not valid with different types within the structure: The pointers of
Ejemplo::datos
are integers ( int
) belonging to Ejemplo
; if instead of integers were other data another pointer would be needed.
If at the end, all the data are going to be of the same type, why not use an internal array?:
struct Ejemplo{
int datos[5]{};
} var;
for (int i = 0; i < 5; ++i){
var.datos[i] = i;
}
1 Being a static member, it does not increase the size of the structure.