31

Is it possible in C++ to iterate through a Struct or Class to find all of its members? For example, if I have struct a, and class b:

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

class b
{
  public:
    int a;
    int b;
  private:
    int c;
}

Would it be possible to loop them to say get a print statement saying "Struct a has int named a, b, c" or "Class b has int named a, b, c"

Theopile
  • 868
  • 3
  • 14
  • 30
  • 22
    No reflection in C++. – chris Sep 27 '13 at 20:03
  • Not in general. If you've left debugging information in the program, a debugger can give you that information, and you might be able to use certain libraries/APIs to inspect your own binary, but that's going to be less fun than, well, pretty much anything... – twalberg Sep 27 '13 at 20:28
  • 2
    Worth considering whether this could be possible as a compile-time activity using meta/template techniques. The information should be available to the compiler - though may need support in a future C++XX. – simon.watts Sep 11 '17 at 14:14

6 Answers6

32

There are a couple of ways to do this, but you need to use some macros to either define or adapt the struct.

You can use the REFLECTABLE macro given in this answer to define the struct like this:

struct A
{
    REFLECTABLE
    (
        (int) a,
        (int) b,
        (int) c
    )
};

And then you can iterate over the fields and print each value like this:

struct print_visitor
{
    template<class FieldData>
    void operator()(FieldData f)
    {
        std::cout << f.name() << "=" << f.get() << std::endl;
    }
};

template<class T>
void print_fields(T & x)
{
    visit_each(x, print_visitor());
}

A x;
print_fields(x);

Another way is to adapt the struct as a fusion sequence (see the documentation). Here's an example:

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

BOOST_FUSION_ADAPT_STRUCT
(
    A,
    (int, a)
    (int, b)
    (int, c)
)

Then you can print the fields as well using this:

struct print_visitor
{
    template<class Index, class C>
    void operator()(Index, C & c)
    {

        std::cout << boost::fusion::extension::struct_member_name<C, Index::value>::call() 
                  << "=" 
                  << boost:::fusion::at<Index>(c) 
                  << std::endl;
    }
};


template<class C>
void print_fields(C & c)
{
    typedef boost::mpl::range_c<int,0, boost::fusion::result_of::size<C>::type::value> range;
    boost::mpl::for_each<range>(boost::bind<void>(print_visitor(), boost::ref(c), _1));
}
Community
  • 1
  • 1
Paul Fultz II
  • 17,682
  • 13
  • 62
  • 59
23

No, it's not possible, because there is no reflection in C++.

villekulla
  • 1,039
  • 5
  • 15
  • 15
    I'm not sure how this isn't an answer. He's telling the OP about a language limitation. This is about as answery as it gets. – Tyler Jandreau Sep 27 '13 at 20:56
  • 14
    @CaptainObvlious: Answers should answer the question. The answer to the question is "no". I mean, the answer could provide a whole mechanism to annotate a specific structure so that someone can iterate some data representing its fields, but that still doesn't iterate the fields of a struct, it iterates the fields of a specially-configured struct. – Steve Jessop Sep 27 '13 at 21:59
  • 3
    The answer to the question is not 'no'. You can easily iterate through the members of a struct and print them using standard C++: `A a; printf(a.a); printf(a.b); printf(a.c);`. There are plenty of ways to make the syntax more like the desired 'loop', using some kind of custom reflection mechanism. – willj Sep 28 '13 at 22:07
  • 9
    @willj: your code is not iteration by any sensible interpretation of the question (and it doesn't even print what the questioner asked for ;-p). And unless you can count on using debug info, custom reflection mechanisms only work on structures that have been somehow annotated, not on the example structures in the question and not on structures that you didn't define yourself. – Steve Jessop Sep 30 '13 at 18:32
  • 1
    @SteveJessop The question places no restriction on annotating the structures involved. Without annotating `struct a` in any way, I can declare `#define LOOP3(op, s, a, b, c) op(s.a); op(s.b); op(s.c)` and `void print(int);`, followed by `a foo; LOOP3(print, foo, a, b, c);`. The same can be done with templates if you object to using the preprocessor. – willj Sep 30 '13 at 19:27
  • 1
    @willj That is not iteration it is enumeration. No one needs to use the preprocessor or templates to manipulate already known variable names. – Trygve Skogsholm Jan 12 '17 at 22:11
  • 5
    Years later, I found this answer significantly more useful than the selected answer. Truly, the answer is `no`. Yes, there are ways to work around and achieve a similar effect, but I don't feel any of the suggestions should be used beyond "extreme debugging". Doing all of this extra work on every single class/struct would be a mess in a production application, in my opinion. – Robert Schwindaman Jul 14 '18 at 03:46
3

If you have members of the same type (as you do in your first specific example) that you want to both (a) have names, and (b) be iterable, then you can combine an array with an enum:

enum names { alice, bob, carl };
struct myStruct;
{
  std::array<int, 3> members;
}

Then you can both

myStruct instance;
// iterate through them...
for (auto elem : instance.members)
{
    // work with each element in sequence
} 
// and call them by name, taking away the need to remember which element is the first, etc.
instance.members[bob] = 100;

Clearly not a general solution, but I've found this useful in my own work.

aquirdturtle
  • 2,038
  • 26
  • 20
3

Provided your member variables are of the same type, you can do something like this that i stole from the GLM library:

class Point
{
    Point();// you must re-implement the default constructor if you need one

    union
    {
        struct
        {
            double x;
            double y;
            double z;
        };
        std::array<double, 3> components;
    };
};

Admittedly this isn't the most elegant solution from a maintainability standpoint, manually keeping count of the number of variables you have is asking for trouble. However It will work without additional libraries or macros and is applicable in most situations that you'd want this behaviour.

Unions don't support automatically generated default constructors so you'll need to write one that tells the object how to initialise the union.

for (double component : point.components)
{
    // do something
}
QCTDev
  • 166
  • 6
1

Assuming that all class members are of the same type, you may employ a C++17 feature called structured binding. Assuming that all members are public this would work:

struct SI
{
    int x;
    int y;
    int z;
};

struct SD
{
    double x;
    double y;
    double z;
};

template<typename T>
void print(const T &val)
{
    const auto& [a, b, c] = val;
    for (auto elem : {a, b, c})
    {
        std::cout << elem << " ";
    }
    std::cout << std::endl;
}

This would work with any struct that has exactly 3 public elements of the same (copyable) type. In case of non-public members the function must be a friend or a member. This approach however cannot be easily extented to arbitrary number of elements.

Dmitry Kuzminov
  • 6,180
  • 6
  • 18
  • 40
1

This is an improved version of QCTDevs answer:

class MyClass
{
    union
    {
        struct Memberstruct
        {
            double test0;
            double test1;
            double test2;
        } m;
        array<double, sizeof( Memberstruct ) / sizeof( double )> memberarray;
    };
    bool test() { &(m.test1) == &(memberarray[1]); }
};

The requirement is still to have all the same datatypes, and you also need to implement the default Constructor, if needed.

It is improved in that you don't need to manually maintain the size of the array.

A drawback is an altered syntax in comparison to the class without this workaround.

Daniel Bauer
  • 478
  • 3
  • 16
  • Another drawback is that it is rather pointless or will lead to undefined behavior, as you can only access the active member of the union. – 303 Jun 14 '22 at 01:31