Range-based for over a struct object

One of the things that I miss the most in the C++ is the ability to iterate over every single field in the POD (plain old data) structure. A basic example from the top of my head is when you need to preprocess the data, received with the different byte endianness (big vs little endian).

What would I want to see

C++11 has introduced an extremely useful construction called range-based for loop. It is great if you only care to perform some actions on every element of the container:

std :: vector < int > vec { 5 , 4 , 3 , 2 , 1 , }; for ( auto & el : vec ) Process ( el );

The case is why aren’t we allowed to do the following?

struct { std :: uint32_t fw_version = 0 ; std :: uint16_t sector_0_version = 0 ; std :: string id = "" ; std :: array < std :: uint8_t , 6 > options {}; } data ; for ( auto & el : data ) Process ( el );

Current language status (C++17)

We’re encountering a problem here: latest standard (C++17) doesn’t allow this. Well, if your class is some sort of a container with the values of the same type, you can implement begin() and end() , but it is impossible for the heterogeneous structures like the one above.

Unfortunately, the only way to iterate over every element of the structure is to write it yourself:

struct { std :: uint32_t fw_version = 0 ; std :: uint16_t sector_0_version = 0 ; std :: string id = "" ; std :: array < std :: uint8_t , 6 > options {}; void Process () { Process ( fw_version ); Process ( sector_0_version ); Process ( id ); Process ( options ); } } data ; data . Process ();

I think you’ll agree with me that it’s awful. Every time you change the structure you have to remember to update the Process() method.

There is, however, a solution: static reflection. This isn’t (yet) part of the language, but we already have some libraries to perform similar kind of tasks. In my opinion, most promising are magic_get by Antony Polukhin (may be included in the boost as the boost::pfr library) and tinyrefl by Manu Sánchez. Since I wasn’t able to build tinyrefl for the Visual Studio, I’ll focus on the magic_get.

Using the compile-time static reflection

With the magic_get library our code transforms into this:

struct { std :: uint32_t fw_version = 0 ; std :: uint16_t sector_0_version = 0 ; std :: string id = "" ; std :: array < std :: uint8_t , 6 > options {}; } data ; boost :: pfr :: for_each_field ( std :: forward < decltype ( data ) > ( data ), []( auto && val ) { Process ( val ); });

I agree it’s not as pretty as the code I wanted to work but imagine my happiness when I was able to get rid of all the boilerplate code I had to write earlier. And since everything is resolved at the compile-time there is no performance penalty.

If you ever had any similar task, check out this library, it may help you a lot.