56

私は構造を持っています

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

構造体のすべてのメンバーを反復処理し、その値を出力したいと思います。何かのようなもの:

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

これはC++でどのように行うことができますか??

4

8 に答える 8

38

おそらく、Boost Fusion/Phoenix を使用して何かをつなぎ合わせることができます。

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

更新: 最近のバージョンのブーストでは、C++11 の型推論を使用できます。

BOOST_FUSION_ADAPT_STRUCT(A,a,b,c);

出力:

1
42
The Answer To LtUaE
于 2013-07-15T17:36:46.487 に答える
24

オブジェクトのデータ メンバーを反復処理することはできません。std::ostreamただし、のストリーム挿入演算子を使用して個別に印刷できます。

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

そしてメインの内部:

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

    std::cout << a;
}

出力:

5
10
アップルソース

これがデモです。

于 2013-07-15T17:27:59.397 に答える
21

これを行うにはいくつかの方法がありますが、いくつかのマクロを使用して構造体を定義または適合させる必要があります。

この回答REFLECTABLEで指定されたマクロを使用して、次のように構造体を定義できます。

struct A
{
    REFLECTABLE
    (
        (int) a,
        (int) b,
        (const char *) c
    )
};

次に、フィールドを反復処理して、次のように各値を出力できます。

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

もう 1 つの方法は、構造体をフュージョン シーケンスとして適合させることです (ドキュメントを参照してください)。次に例を示します。

struct A
{
    int a;
    int b;
    const char * c;
};

BOOST_FUSION_ADAPT_STRUCT
(
    A,
    (int, a)
    (int, b)
    (const char *, c)
)

次に、これを使用してフィールドも印刷できます。

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)));
}
于 2013-11-30T04:55:30.120 に答える
15

C++ はそのままではリフレクションをサポートしていないため、コア言語内で求めていることは不可能です。

さまざまなライブラリがそのような機能を提供しようとしています。通常、いくつかのメソッドまたはマクロを使用してフィールドを登録することで、舞台裏でフィールドを何らかのコレクションに保存し、反復できるようにします。

于 2013-07-15T17:28:43.567 に答える
7

標準の C++ で構造体のメンバーを反復処理できますか?

いいえ、標準のc++は、求めていることを達成するための方法を提供していません。コンテナーの要素を「反復」します。特定の型のメンバーを反復することはできません。

"リフレクション" (このタイプの機能は C++ の一部ではないため、最も頻繁に参照されます)。


c++11std::tuple<int,int,char*>では、 の代わりに a を使用できます。同じ種類struct Aの要素が格納され、反復処理がはるかに簡単になります (テンプレートマジックを使用)。

'a'要素には からまでの範囲の名前はありませんが、'c'そのように印刷したい場合は、もちろんこれはいくつかの追加のコード行で実現できます。

特定の要素にアクセスするには、 std::get<N> (your_tuple)whereNは 0 からstd::tuple_size<std::tuple<int,int,char*>>::value - 1(つまり 2) までの範囲の整数です。


于 2013-07-15T17:31:35.747 に答える
3

@Paul が提案したように、私は BOOST_FUSION_ADAPT_STRUCT を自己記述の for_each_member 関数で使用します。

/**
 * \brief Allows iteration on member name and values of a Fusion adapted struct.
 * 
 *  
 * BOOST_FUSION_ADAPT_STRUCT(ns::point,
 *      (int, x)
 *      (int, y)
 *      (int, z));
 *
 * template<class T>
 * print_name_and_value(const char* name, T& value) const {
 *    std::cout << name << "=" << value << std::endl;
 * } 
 *
 * 
 * int main(void) {
 *  
 *  ns::point mypoint;
 *
 *  
 *      boost::fusion::for_each_member(mypoint, &print_name_and_value);
 *
 *
 * }
 *
 */
#ifndef BOOST_FUSION_FOR_EACH_MEMBER_HPP
#define BOOST_FUSION_FOR_EACH_MEMBER_HPP

#include <functional>

#include <boost/fusion/include/adapt_struct.hpp>

#include <boost/fusion/sequence/intrinsic/begin.hpp>
#include <boost/fusion/sequence/intrinsic/end.hpp>
#include <boost/fusion/sequence/intrinsic/front.hpp>
#include <boost/fusion/iterator/equal_to.hpp>
#include <boost/fusion/iterator/next.hpp>
#include <boost/fusion/iterator/deref.hpp>
#include <boost/fusion/iterator/distance.hpp>
#include <boost/fusion/support/category_of.hpp>
#include <boost/mpl/bool.hpp>

namespace boost { namespace fusion {

namespace detail {

  template <typename First, typename Last, typename F>
  inline void
  for_each_member_linear(First const& first,
      Last const& last,
      F const& f,
      boost::mpl::true_) {}

  template <typename First, typename Last, typename F>
  inline void
  for_each_member_linear(First const& first,
      Last const& last,
      F const& f,
      boost::mpl::false_) {

      f(
                extension::struct_member_name<
                    typename First::seq_type, First::index::value
                >::call(),
                *first
            );

      for_each_member_linear(
          next(first),
          last,
          f,
          result_of::equal_to< typename result_of::next<First>::type, Last>()
      );
  }

  template <typename Sequence, typename F>
  inline void
  for_each_member(Sequence& seq, F const& f) {

    detail::for_each_member_linear(
      fusion::begin(seq),
      fusion::end(seq),
      f,
      result_of::equal_to<
        typename result_of::begin<Sequence>::type,
        typename result_of::end<Sequence>::type>()
    );
  }

}

  template <typename Sequence, typename F>
  inline void
  for_each_member(Sequence& seq, F f) {
    detail::for_each_member(seq, f);
  }

}}

#endif 
于 2014-07-29T21:11:42.230 に答える