Итерация над структурой в 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 ++?
- Обновите поле MongoDB, используя значение другого поля
- Solr документы с дочерними элементами?
- Структура агрегации Mongodb: используется ли индекс использования группы?
- Как суммировать все поля в дополнительном документе MongoDB?
- Можно ли удалить ребенка из коллекции и решить проблемы в SaveChanges?
- Найти в двойном вложенном массиве MongoDB
- Как фильтровать массив в подзадаче с помощью MongoDB
- Получить имена всех ключей в коллекции
- Инициализировать определение вложенной структуры в Голанге
- Совокупный $ lookup Общий размер документов в соответствующем конвейере превышает максимальный размер документа
- Соответствие ObjectId для String для $ graphLookup
- $ lookup для ObjectId's в массиве
- Групповой результат на 15 минут времени в MongoDb
Возможно, вы можете связать что-то вместе, используя 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
где N
является интегралом от 0 до std::tuple_size
(т.е. 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