Question

I'm wondering on how to properly loop over the members of a plain old data type, in order to get some type information on them. That is :

struct my_pod
{
    int a;
    double b;
};

template<typename POD>
void loopOverPOD()
{
    for_each(POD, member) // The magic part
    {
        // member::type should be for my_pod int, then double
        typename member::type i;
        // member::size_of should be equal to sizeof(int) then sizeof(double)
        // Trivial if we can have member::type information.
        int size = member::size_of;
        // member::offset_of should be equal to 0, then sizeof(int)
        // Trivial if we can have member::size_of information.
        int offset = member::offset_of;
    }
}

As far as I know in C++, we can't do easy type introspection without doing some tricky plays with templates. But here, I can't find a concrete solution with templates, even with the use of macro in fact. And the problem is more about me rather than about the existence of a solution. :-)

I'm not necessarily asking for a solution that would not be intrusive.

Thanks in advance.

Was it helpful?

Solution

You could use boost.fusions ADAPT_STRUCT to turn your POD into a sequence and then use fusions for_each to apply a function object to each member. This is non-intrusive, your POD type will remain POD.

The good thing is that you could even put the ADAPT_STRUCT macros in a (header-) file separate from your struct definitions and only use them in code where you need to iterate.

The flip side is that this macro requires the redundancy of mentioning both the type and the name of the members again. I imagine that at some point fusion will use C++11 features to get rid of that redundancy (mentioning the type again). In the mean time, it is possible to create a macro that will declare the struct and the ADAP_STRUCT part.

OTHER TIPS

If you use C++14 and newer, you can use Boost.Precise and Flat Reflection (https://github.com/apolukhin/magic_get/) for looping over your POD and boost::typeindex::type_id_runtime(field) to print type:

#include <iostream>
#include <boost/pfr/precise.hpp>
#include <boost/pfr/flat.hpp>
#include <boost/type_index.hpp>

struct my_pod
{
    int a;
    double b;
};

struct my_struct
{
    char c;
    my_pod pod;
};

int main() {
    my_pod val{1, 2.5};

    my_struct var{'a', 1, 2.5};

    std::cout <<  "Flat:\n";
    boost::pfr::flat_for_each_field(var, [](const auto& field, std::size_t idx) {
        std::cout << idx << ": " << boost::typeindex::type_id_runtime(field) << "; value: " << field << '\n';
    });

    std::cout <<  "\nNot Flat:\n";
    boost::pfr::for_each_field(var, [](const auto& field, std::size_t idx) {
        using namespace boost::pfr::ops;
        std::cout << idx << ": " << boost::typeindex::type_id_runtime(field) << "; value: " << field << '\n';
    });
}

Output for this example:

Flat:
0: char; value: a
1: int; value: 1
2: double; value: 2.5

Not Flat:
0: char; value: a
1: my_pod; value: {1, 2.5}

Though I'm not sure how to get offset in this case...

C++ has no construct to iterate through members of a structure.

There exists however a standard type std::tuple for which you can use templates to recursively iterate through its elements at compile time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top