Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to iterate over all elements in a struct or class?

Tags:

c++

c++11

Is it possible to iterate over all elements in a struct or class?

For example if I have a struct of three elements of different type:

struct A {
    classA a;
    classB b;
    classC c;
};

then I need some iterator such that a method next() would give me the value of the next element. The problem is that as you see, the values have different types.

like image 982
user3111311 Avatar asked Dec 17 '13 16:12

user3111311


2 Answers

Nope, not with the language as it is.

You could do it by deriving your classes from a common base, and then implementing your own iterator to return pointers to each item as the iterator is traversed.

Alternatively put the items in a std::vector and use that to provide the iteration.

like image 133
Sean Avatar answered Nov 10 '22 00:11

Sean


No, there is no reflection in C++, (yet, there are murmurs about static reflection coming one day).

Anyway, there is a way to work around this, to an extent - first of all, you'll need a (temporary) tuple with references to your data members.

Then you will need a construct "iterating" over the tuple, such as:

void applyToAll() { }

template <typename Lambda, typename... Lambdas>
void applyToAll(Lambda&& closure, Lambdas&&... closures) {
    std::forward<Lambda>(closure)();
    applyToAll(std::forward<Lambdas>(closures)...);
}

// use your favourite sequence-making trick
template <unsigned... Is>
struct _Sequence {
    typedef _Sequence<Is...> type;
};

template <unsigned Max, unsigned... Is>
struct _MakeSequence : _MakeSequence<Max - 1, Max - 1, Is...> { };

template <unsigned... Is>
struct _MakeSequence<0, Is...> : _Sequence<Is...> { };

template <typename Tuple, typename Functor, unsigned... Is>
void _foreachElemInTuple(_Sequence<Is...>, Tuple&& t, Functor&& f) {
    applyToAll(
       [&]{ std::forward<Functor>(f)(std::get<Is>(std::forward<Tuple>(t))); }...
    );
}

template <typename Tuple, typename Functor>
void foreachElemInTuple(Tuple&& t, Functor&& f) {
    _foreachElemInTuple(
         _MakeSequence<std::tuple_size<
              typename std::decay<Tuple>::type>::value>(),
         std::forward<Tuple>(t), std::forward<Functor>(f)
    );
}

Then you can call foreachElemInTuple(yourTuple, some_adapter()).

Your adapter will look like:

struct some_adapter {
    template <typename... Args>
    // A little bit of C++14, you can also just -> decltype the thing
    decltype(auto) operator()(Args&& ... args) const {
        return doStuff(std::forward<Args>(args)...);
    }
};
like image 42
ScarletAmaranth Avatar answered Nov 09 '22 23:11

ScarletAmaranth