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

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

For example, if I have a structure of three elements of different types:

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

then I need some iterator so that the next () method gives me the value of the next element. The problem is that, as you see, the values ​​have different types.

+4
source share
3 answers

No, not with the language as it is.

You can do this by deriving your classes from a common base, and then implementing your own iterator to return pointers to each element as the iterator passes.

Alternatively, put the elements in std::vectorand use them to provide iteration.

+4
source

, ++ ( ).

, , - () .

"" , :

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

foreachElemInTuple(yourTuple, some_adapter()).

:

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)...);
    }
};
+3

, . , , , . , ScarletAmaranth, std::tuple .

The following program shows how to get such a tuple using std::forward_as_tuple, and another way to do the repetition by compiletime recursion without an auxiliary device.

#include <tuple>

/*  You want to be able do something with the values of the members of an `A` 
    in turn.
*/
struct A
{
    char ch;
    int i;
    double d;
    // May also have members of class type. It doesn't matter 
};

/*  1) Provide yourself with the means of creating a sequence that contains
    references to the data members of a given `A`
*/
std::tuple<char const &, int const &, double const &> get_A_vals(A const & a)
{
    return std::forward_as_tuple(a.ch,a.i,a.d);
}


/*  2) Provide yourself with a means of applying some operation, `Func`, 
    to each element of an `std::tuple`
*/
template<size_t I = 0, typename Func, typename ...Ts>
typename std::enable_if<I == sizeof...(Ts)>::type
for_each_in_tuple(std::tuple<Ts...> const &, Func) {}

template<size_t I = 0, typename Func, typename ...Ts>
typename std::enable_if<I < sizeof...(Ts)>::type
for_each_in_tuple(std::tuple<Ts...> const & tpl, Func func) 
{
    func(std::get<I>(tpl));
    for_each_in_tuple<I + 1>(tpl,func);
}

/* 3) Combine 1) and 2) to apply `Func` over the members of an `A`
*/
template<typename Func>
void for_each_in_A(A const & a, Func func)
{
    for_each_in_tuple(get_A_vals(a),func);
}

// Testing...

#include <iostream>

// A specimen operation: just prints its argument
struct printer
{
    template<typename T>
    void operator () (T && t)
    {
        std::cout << t << std::endl;
    }
};

int main()
{
    A a{'a',1,2.0};
    for_each_in_A(a,printer());
    return 0;
}

// EOF

Program Outputs:

a
1
2

If you have control over structures or classes whose members you need to iterate over, you might consider whether it is practical to simply drop them and use them everywhere std::tuple.

Code built with gcc 4.8.2 and 3.3 clang, -std=c++11.

0
source

All Articles