0

I have some C++ code like this:

struct UpLeft {
    int m_up_left;
};

struct UpRight {
    int m_up_right;
};

struct DownLeft {
    int m_down_left;
};

struct DownRight {
    int m_down_right;
};

struct B {
    UpLeft up_left;
    UpRight up_right;
    DownLeft down_left;
    DownRight down_right;
};

struct A {
    B b;
};

int foo() {
    // some computation, won't always return 0.
    return 0;
}

void setUpLeft(A &a) { a.b.up_left.m_up_left = foo(); }

void setUpRight(A &a) { a.b.up_right.m_up_right = foo(); }

void setDownLeft(A &a) { a.b.down_left.m_down_left = foo(); }

void setDownRight(A &a) { a.b.down_right.m_down_right = foo(); }

It is called like this:

A a{};
setUpLeft(a);
setUpRight(a);
setDownLeft(a);
setDownRight(a);

Instead, I want to delete the set functions and do something like this:

// pseudo-code
for (x = {up_left, up_right, down_left, down_right}) {
    a.b.x.x_m = foo();
}

So a.b.x.x_m becomes a.b.up_left.up_left_m, then a.b.up_right.up_right_m, etc.

Is there a way to accomplish this in C++?

ChrisMM
  • 8,448
  • 13
  • 29
  • 48
user3100212
  • 101
  • 1
  • 5
  • 2
    it is possible, but it will not be much simpler and requires you write functions very similar to the ones you already have and much more code. If the question is whether C++ can do this out of the box, then no. – 463035818_is_not_an_ai Mar 29 '23 at 12:50
  • Why not just use aggregate initialization? https://godbolt.org/z/GccvGjvnv – Marek R Mar 29 '23 at 13:07

1 Answers1

0

Well, technically you could use pointers to data members, and then apply them to your object you try to modify. A bit simplified example (because yours is extremely superfluous with all these structs holding single ints):

Let's have a structure with 3 membes

struct Foo
{
    int a;
    int b;
    int c;
};

void print(const Foo& f)
{
    std::cout << f.a << ", " << f.b << ", " << f.c << "\n";
}

Pointer to int member can be defined like this

using foo_member_ptr = int Foo::*;

and applied like this

foo_member_ptr yourPtr = &Foo::a;
obj.*yourPtr = whatever;

So, you can define a collection of pointers to members {a, b, c} and collection of expected values, e.g. {4, 5, 6} and then apply them in the loop. Complete example:

    Foo foo{1, 2, 3};
    using foo_member_ptr = int Foo::*;
    auto memberPtrList = std::vector<foo_member_ptr>({&Foo::a, &Foo::b, &Foo::c});
    auto nums = std::vector<int>({4, 5, 6});
    print(foo);
    for (int i = 0; i < 3; i++)
    {
        foo.*memberPtrList[i] = nums[i];
    }
    print(foo);

But, just because you can do it doesn't necessarily mean that you should. Probably much better approach would be to modify your design and actually use some structure with {key, value} pairs, like std::unordered_map. Then your code could become like this:

struct B {
  std::unordered_map<std::string, int> corners;
};

and later:

b.corners["upperLeft"] = 666;
pptaszni
  • 5,591
  • 5
  • 27
  • 43