Iterate Through Struct and Class Members

Iterate through Struct and Class Members

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));
}

Iterating through Struct members

You apply reflection in pretty much the same way as normal, using Type.GetFields:

MyStruct structValue = new MyStruct(...);

foreach (var field in typeof(MyStruct).GetFields(BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public))
{
Console.WriteLine("{0} = {1}", field.Name, field.GetValue(structValue));
}

Note that if the struct exposes properties (as it almost certainly should) you could use Type.GetProperties to get at those.

(As noted in comments, this may well not be a good thing to do in the first place, and in general I'm suspicious of user-defined structs, but I thought I'd include the actual answer anyway...)

EDIT: Now it seems you're interested in setting the fields, that's slightly more complicated due to the way value types work (and yes, this really shouldn't be a struct.) You'll want to box once, set values on the single boxed instance, and then unbox at the end:

object boxed = new MyStruct();

// Call FieldInfo.SetValue(boxed, newValue) etc

MyStruct unboxed = (MyStruct) boxed;

How to iterate through a struct's fields?


public struct GridNeighbours {

public enum Cardinal { North, East, South, West }

public static Vector2Int[] Neighbours = { new Vector2Int(0, 1), new Vector2Int(1, 0), new Vector2Int(0, -1), new Vector2Int(-1, 0) };

public Vector2Int this[Cardinal dirn] {
get { return this[(int)dirn]; }
set { this[(int)dirn] = value; }
}

public Vector2Int this[int dirn] {
get { return Neighbours[dirn]; }
set { Neighbours[dirn] = value; }
}
}

Example use:

var cell = new GridNeighbours();
var NorthNeighbour = cell[Cardinal.North];
Assert(cell[Cardinal.South] == cell[2]); // This is true!

===

Alternatively, if you want "direct" properties:

public struct GridNeighbours {
public enum Cardinal { North, East, South, West }

public static Vector2Int[] Neighbours = { new Vector2Int(0, 1), new Vector2Int(1, 0), new Vector2Int(0, -1), new Vector2Int(-1, 0) };

public static Vector2Int North { get { return Neighbours[0]; } set { Neighbours[0] = value; } }
public static Vector2Int East { get { return Neighbours[1]; } set { Neighbours[1] = value; } }
public static Vector2Int South { get { return Neighbours[2]; } set { Neighbours[2] = value; } }
public static Vector2Int West { get { return Neighbours[3]; } set { Neighbours[3] = value; } }
}

Iterate through struct by variable name

This may well be easier than you expect. First, some caveats:

  1. Arrays are guaranteed, by the standard, to be contiguous; that is, there's no padding inserted between them, and the array itself is aligned with the alignment requirements of the element type.

  2. Structs have no such restrictions; they can be subject to arbitrary padding. However, a given implementation (at a given version) will do this the same way in all translation units (otherwise, how else could the same structure definition be used to pass data across translation units?). The usual way this is done is fairly sane, especially when the struct contains only members of a single type. For such a struct, the alignment usually matches the largest alignment of the members, and there's usually no padding because all members have the same alignment.

In your case, your array of 1024 floats and your struct with 1024 float members almost certainly have exactly the same memory layout. This is absolutely not guaranteed by the standard, but your compiler may document its struct layout rules, and you can always assert the sizes and alignments match in your unit tests (you do have unit tests, right?)

Given those caveats, you will almost certainly be able to simply reinterpret_cast (or memcpy) between the two.



Related Topics



Leave a reply



Submit