0

I have a C++ structure

struct Line {
  int date;
  int time;
  float open;
  float high;
  float low;
  float close;
  float sd;
  float long_mo;
  float short_mo;
};

8 fields. I want to fill it using loop.

int fields_count=1;
while (fields_count<=8) {
  // get digit from outer sourse. I dont need help here.
  // First iteration puts to 1 field, Second iteration puts to 2 field and so on up to last field of struct 
  fields_count++;
}
Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
Kosmonavt
  • 191
  • 2
  • 14

3 Answers3

2

Something like this:

#include<stddef.h>

struct Line {
  int date;
  int time;
  float open;
  float high;
  float low;
  float close;
  float sd;
  float long_mo;
  float short_mo;
};

char types [] = "iifffffff";
int offsets [] = {
  offsetof (Line, date),
  offsetof (Line, time),
  offsetof (Line, open),
  offsetof (Line, high),
  offsetof (Line, low),
  offsetof (Line, close),
  offsetof (Line, sd),
  offsetof (Line, long_mo),
  offsetof (Line, short_mo)
}

Line line;

for (int i = 0; i < 9; i++) {
  char *field_ptr = ((char*)&line) + offsets [i];

  if (types [i] == 'i')
    *(int*)field_ptr = readInt ();
  else if (types [i] == 'f')
    *(float*)field_ptr = readFloat ();
}
Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
  • A nice example of the C++ motto "you don't pay for what you don't use". In this case, C++ does not have reflection (because reflection isn't free; to properly support reflection is a lot of infrastructure and data to lug around, which may never be used). Mikhail's example shows how to build your own reflection, which for this scenario good enough is definitely good enough. – Eljay Mar 22 '19 at 17:14
1

In C++20 you could use expansion statements to iterate on aggregates:

auto my_line = Line{};
auto fields_count = std::size_t{0};
for...(auto& member : my_line) {
    member = get_digit(fields_count++);
}

You can even get the type of the member being iterated on:

auto my_line = Line{};
auto fields_count = std::size_t{0};
for...(auto& member : my_line) {
    using type = std::remove_cvref_t<decltype(member)>;
    member = get_digit<type>(fields_count++);
}
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
0

Sadly there is no reflection in C++, so there isn't a good way to do what you want.

With modern C++ you could do something like this:

#include <cstddef>
#include <iostream>
#include <tuple>
#include <utility>

struct Line
{
    int date;
    int time;
    float open;
    float high;
    float low;
    float close;
    float sd;
    float long_mo;
    float short_mo;
};

template <typename ...P, std::size_t ...I, typename F>
void for_each_tuple_elem_low(std::tuple<P...> t, std::index_sequence<I...>, F &&func)
{
    (void(func(std::get<I>(t))) , ...);
}

template <typename ...P, typename F> void for_each_tuple_elem(std::tuple<P...> t, F &&func)
{
    for_each_tuple_elem_low(t, std::make_index_sequence<sizeof...(P)>{}, func);
}

int main()
{
    Line obj;
    auto &[x1,x2,x3,x4,x5,x6,x7,x8,x9] = obj;
    auto tuple = std::tie(x1,x2,x3,x4,x5,x6,x7,x8,x9);

    int i = 0;
    for_each_tuple_elem(tuple, [&](auto &ref)
    {
        ref = i++;
    });
}

Here, the boilerplate is reduced to typing out the names of the structured bindings twice: x1,x2,x3,x4,x5,x6,x7,x8,x9.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207