是否可以迭代结构或类中的所有元素?

时间:2013-12-17 16:39:39

标签: c++ c++11

是否可以迭代结构或类中的所有元素?

例如,如果我有三个不同类型的元素的结构:

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

然后我需要一些迭代器,这样方法next()会给我一个值 下一个元素。问题是,如您所见,值具有不同的类型。

3 个答案:

答案 0 :(得分:4)

不,不是用这种语言。

你可以通过从公共库中派生类来实现它,然后实现自己的迭代器,以便在遍历迭代器时返回指向每个项的指针。

或者将项目放在std::vector中并使用它来提供迭代。

答案 1 :(得分:4)

不,C ++中没有任何反映,(但是,有一天会出现关于静态反射的杂音)。

无论如何,有一种方法可以解决这个问题 - 首先,你需要一个(临时的)元组来引用你的数据成员。

然后你需要一个构造“迭代”元组,例如:

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

答案 2 :(得分:0)

正如其他人所说,你不能直接迭代a的数据成员 类。但是,当然也可以间接地做到这一点 您可以访问要迭代的每个数据成员。这个想法 根据ScarletAmaranth的解决方案,在essense中,迭代std::tuple 对那些数据成员的引用。

以下程序显示了如何使用std::forward_as_tuple获取这样的元组, 和另一种通过编译时递归进行迭代的方法 辅助器具。

#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

程序输出:

a
1
2

如果您可以控制您需要的成员的结构或类 迭代,您可以考虑放弃它们是否切实可行 并在任何地方使用相应的std::tuple

使用gcc 4.8.2和clang 3.3,-std=c++11构建的代码。