Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating over a struct in C++

Tags:

c++

struct

I have a structure

typedef struct A
{
    int a;
    int b;
    char * c;
}aA;

I want to iterate over each an every member of the structure and print its value. Something like:

void print_struct_value(struct *A)
{
    for each member of struct A
    cout << "struct name . member name" << "value";
}

How can this be done in C++ ??

like image 756
msd_2 Avatar asked Jul 15 '13 17:07

msd_2


4 Answers

Perhaps you can string something together using Boost Fusion/Phoenix:

See it live on Coliru!

#include <boost/fusion/adapted/struct.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/phoenix/phoenix.hpp>
using boost::phoenix::arg_names::arg1;

#include <string>
#include <iostream>

struct A
{
    int a;
    int b;
    std::string c;
};

BOOST_FUSION_ADAPT_STRUCT(A, (int,a)(int,b)(std::string,c));

int main()
{
    const A obj = { 1, 42, "The Answer To LtUaE" };

    boost::fusion::for_each(obj, std::cout << arg1 << "\n");
}

Update: Recent versions of boost can use C++11 type deduction:

BOOST_FUSION_ADAPT_STRUCT(A,a,b,c);

Output:

1
42
The Answer To LtUaE
like image 92
sehe Avatar answered Nov 18 '22 07:11

sehe


You can't iterate over an object's data members. You can use std::ostream's stream insertion operator to print individually however:

struct A
{
    int a;
    int b;
    std::string c;

    friend std::ostream& operator <<(std::ostream& os, A const& a)
    {
        return os << a.a << '\n'
                  << a.b << '\n'
                  << a.c << '\n';
    }
};

And inside main:

int main()
{
    A a = {5, 10, "apple sauce"};

    std::cout << a;
}

Output:

5
10
apple sauce

Here is a demo.

like image 41
David G Avatar answered Nov 18 '22 06:11

David G


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,
        (const char *) 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;
    const char * c;
};

BOOST_FUSION_ADAPT_STRUCT
(
    A,
    (int, a)
    (int, b)
    (const char *, 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(), _1, boost::ref(c)));
}
like image 21
Paul Fultz II Avatar answered Nov 18 '22 06:11

Paul Fultz II


C++ does not support reflection out of the box, so what you are asking for is impossible within the core language.

Various libraries try to provide such functionality, typically by making you register your fields through some methods or macros, which will behind the scene save them into a collection of some sort, on which you can iterate.

like image 15
small_duck Avatar answered Nov 18 '22 08:11

small_duck