Итерация над структурой в C ++

У меня есть структура

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 ++?

Возможно, вы можете связать что-то вместе, используя Boost Fusion / Phoenix:

Смотрите, живите на Колиру !

 #include  #include  #include  using boost::phoenix::arg_names::arg1; #include  #include  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"); } 

Вывод:

 1 42 The Answer To LtUaE 

Вы не можете перебирать элементы данных объекта. Вы можете использовать оператор ввода std::ostream для печати отдельно:

 struct A { int a; int b; std::string c; friend std::ostream& operator <<(std::ostream& os, A const& a) { return os << aa << '\n' << ab << '\n' << ac << '\n'; } }; 

И внутри основной:

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

Вывод:

5
10
яблочный соус

Вот демонстрация.

Есть несколько способов сделать это, но вам нужно использовать некоторые macros для определения или адаптации структуры.

Вы можете использовать макрос REFLECTABLE указанный в этом ответе, для определения структуры следующим образом:

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

И затем вы можете перебирать поля и печатать каждое значение следующим образом:

 struct print_visitor { template void operator()(FieldData f) { std::cout << f.name() << "=" << f.get() << std::endl; } }; template void print_fields(T & x) { visit_each(x, print_visitor()); } A x; print_fields(x); 

Другой способ – адаптировать структуру как последовательность слияния (см. Документацию ). Вот пример:

 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 void operator()(Index, C & c) { std::cout << boost::fusion::extension::struct_member_name::call() << "=" << boost:::fusion::at(c) << std::endl; } }; template void print_fields(C & c) { typedef boost::mpl::range_c::type::value> range; boost::mpl::for_each(boost::bind(print_visitor(), _1, boost::ref(c))); } 

C ++ не поддерживает reflection из коробки, поэтому то, о чем вы просите, невозможно на основном языке.

Различные библиотеки пытаются обеспечить такую ​​функциональность, как правило, заставляя вас регистрировать свои поля с помощью некоторых методов или макросов, которые позади сцены сохраняют их в виде коллекции, в которой вы можете выполнять итерацию.

Можно ли перебирать элементы структуры в стандартном c ++?

Нет, стандартный c ++ не предоставляет метод для выполнения того, что вы просите, вы «итерации» элементов контейнера – вы не можете перебирать элементы определенного типа.

« reflection » (поскольку этот тип функции чаще всего упоминается не является частью C ++).


в c ++ 11 вы можете использовать std::tuple вместо вашей struct A , он будет хранить одни и те же элементы и намного легче перебирать (используя магию шаблона ).

элементы не будут иметь имена от 'a' до 'c' но если вы хотите напечатать его таким образом, это, конечно, может быть выполнено с помощью некоторых дополнительных строк кода.

Чтобы получить доступ к определенному элементу, вы будете использовать std::get (your_tuple) где N является интегралом от 0 до std::tuple_size>::value - 1 (т.е. 2).


Как предложил @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 * 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  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  namespace boost { namespace fusion { namespace detail { template  inline void for_each_member_linear(First const& first, Last const& last, F const& f, boost::mpl::true_) {} template  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::type, Last>() ); } template  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::type, typename result_of::end::type>() ); } } template  inline void for_each_member(Sequence& seq, F f) { detail::for_each_member(seq, f); } }} #endif 
  • Несколько условий соединения с помощью оператора $ lookup
  • массивы нулевой длины
  • Класс vs Struct только для данных?
  • Что лучше для хранилища данных Struct / Classes?
  • Получить только запрошенный элемент в массиве объектов в коллекции MongoDB
  • MongoDB: структура агрегирования: получить последний датированный документ для идентификатора группы
  • C, чтение из файла в структуру
  • Сложение структуры в C ++
  • Как выглядит заголовок zlib?
  • Создание структуры для агрегирования
  • Экспорт структуры агрегации mongodb в новую коллекцию
  • Давайте будем гением компьютера.