I have a structure
typedef struct A
{
int a;
int b;
char * c;
}aA;
I want to iterate over each an every member of the structure
Perhaps you can string something together using Boost Fusion/Phoenix:
See it live on 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");
}
Update: Recent versions of boost can use C++11 type deduction:
BOOST_FUSION_ADAPT_STRUCT(A,a,b,c);
Output:
1
42
The Answer To LtUaE
If all fields in the structure are the same, you can do
template <typename S> uint64_t* get_begin(S *s)
{
return (uint64_t*)s;
}
template <typename S> uint64_t* get_end(S *s)
{
return (uint64_t*)((uint8_t*)s+sizeof(*s));
}
struct statistics_s {
uint64_t f1;
uint64_t f2;
} statistics;
for (uint64_t* p = get_begin(&statistics);p < get_end(&statistics);p++)
printf("%lu ", *p);
There are a couple of ways to do this, but you need to use some macros to either define or adapt the struct.
You can use the REFLECTABLE
macro given in this answer to define the struct like this:
struct A
{
REFLECTABLE
(
(int) a,
(int) b,
(const char *) c
)
};
And then you can iterate over the fields and print each value like this:
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);
Another way is to adapt the struct as a fusion sequence (see the documentation). Here's an example:
struct A
{
int a;
int b;
const char * c;
};
BOOST_FUSION_ADAPT_STRUCT
(
A,
(int, a)
(int, b)
(const char *, c)
)
Then you can print the fields as well using this:
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)));
}
As suggested by @Paul I use BOOST_FUSION_ADAPT_STRUCT with a self written for_each_member function :
/**
* \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
I wrote a version without Boost or other third-party library, which has been tested using GCC 4.9(c++11), clang 5.0(c++11), VS 2008, VS 2019.
#include <iostream>
#include <string>
#define REFLECTION_WITH_FIELD_NAME 1
#define _PP_EVAL(...) __VA_ARGS__
#define _PP_EAT(...)
#define _PP_EMPTY
#define _PP_STR2(x) #x
#define _PP_STR(x) _PP_STR2(x)
#define _PP_MAP01(f, x) f(x)
#define _PP_MAP02(f, x, ...) f(x) _PP_EVAL(_PP_MAP01(f, __VA_ARGS__))
#define _PP_MAP03(f, x, ...) f(x) _PP_EVAL(_PP_MAP02(f, __VA_ARGS__))
#define _PP_MAP04(f, x, ...) f(x) _PP_EVAL(_PP_MAP03(f, __VA_ARGS__))
#define _PP_MAP05(f, x, ...) f(x) _PP_EVAL(_PP_MAP04(f, __VA_ARGS__))
#define _PP_MAP06(f, x, ...) f(x) _PP_EVAL(_PP_MAP05(f, __VA_ARGS__))
#define _PP_MAP07(f, x, ...) f(x) _PP_EVAL(_PP_MAP06(f, __VA_ARGS__))
#define _PP_MAP08(f, x, ...) f(x) _PP_EVAL(_PP_MAP07(f, __VA_ARGS__))
#define _PP_MAP09(f, x, ...) f(x) _PP_EVAL(_PP_MAP08(f, __VA_ARGS__))
#define _PP_MAP10(f, x, ...) f(x) _PP_EVAL(_PP_MAP09(f, __VA_ARGS__))
#define _PP_MAP11(f, x, ...) f(x) _PP_EVAL(_PP_MAP10(f, __VA_ARGS__))
#define _PP_MAP12(f, x, ...) f(x) _PP_EVAL(_PP_MAP11(f, __VA_ARGS__))
#define _PP_MAP13(f, x, ...) f(x) _PP_EVAL(_PP_MAP12(f, __VA_ARGS__))
#define _PP_MAP14(f, x, ...) f(x) _PP_EVAL(_PP_MAP13(f, __VA_ARGS__))
#define _PP_MAP15(f, x, ...) f(x) _PP_EVAL(_PP_MAP14(f, __VA_ARGS__))
#define _PP_MAP16(f, x, ...) f(x) _PP_EVAL(_PP_MAP15(f, __VA_ARGS__))
#define _PP_MAP17(f, x, ...) f(x) _PP_EVAL(_PP_MAP16(f, __VA_ARGS__))
#define _PP_MAP18(f, x, ...) f(x) _PP_EVAL(_PP_MAP17(f, __VA_ARGS__))
#define _PP_MAP19(f, x, ...) f(x) _PP_EVAL(_PP_MAP18(f, __VA_ARGS__))
#define _PP_MAP20(f, x, ...) f(x) _PP_EVAL(_PP_MAP19(f, __VA_ARGS__))
#define _PP_MAP21(f, x, ...) f(x) _PP_EVAL(_PP_MAP20(f, __VA_ARGS__))
#define _PP_MAP22(f, x, ...) f(x) _PP_EVAL(_PP_MAP21(f, __VA_ARGS__))
#define _PP_MAP23(f, x, ...) f(x) _PP_EVAL(_PP_MAP22(f, __VA_ARGS__))
#define _PP_MAP24(f, x, ...) f(x) _PP_EVAL(_PP_MAP23(f, __VA_ARGS__))
#define _PP_MAP25(f, x, ...) f(x) _PP_EVAL(_PP_MAP24(f, __VA_ARGS__))
#define _PP_MAP26(f, x, ...) f(x) _PP_EVAL(_PP_MAP25(f, __VA_ARGS__))
#define _PP_MAP27(f, x, ...) f(x) _PP_EVAL(_PP_MAP26(f, __VA_ARGS__))
#define _PP_MAP28(f, x, ...) f(x) _PP_EVAL(_PP_MAP27(f, __VA_ARGS__))
#define _PP_MAP29(f, x, ...) f(x) _PP_EVAL(_PP_MAP28(f, __VA_ARGS__))
#define _PP_MAP30(f, x, ...) f(x) _PP_EVAL(_PP_MAP29(f, __VA_ARGS__))
#define _PP_MAP31(f, x, ...) f(x) _PP_EVAL(_PP_MAP30(f, __VA_ARGS__))
#define _PP_MAP32(f, x, ...) f(x) _PP_EVAL(_PP_MAP31(f, __VA_ARGS__))
#define _PP_MAP33(f, x, ...) f(x) _PP_EVAL(_PP_MAP32(f, __VA_ARGS__))
#define _PP_MAP34(f, x, ...) f(x) _PP_EVAL(_PP_MAP33(f, __VA_ARGS__))
#define _PP_MAP35(f, x, ...) f(x) _PP_EVAL(_PP_MAP34(f, __VA_ARGS__))
#define _PP_MAP36(f, x, ...) f(x) _PP_EVAL(_PP_MAP35(f, __VA_ARGS__))
#define _PP_MAP37(f, x, ...) f(x) _PP_EVAL(_PP_MAP36(f, __VA_ARGS__))
#define _PP_MAP38(f, x, ...) f(x) _PP_EVAL(_PP_MAP37(f, __VA_ARGS__))
#define _PP_MAP39(f, x, ...) f(x) _PP_EVAL(_PP_MAP38(f, __VA_ARGS__))
#define _PP_MAP40(f, x, ...) f(x) _PP_EVAL(_PP_MAP39(f, __VA_ARGS__))
#define _PP_MAP41(f, x, ...) f(x) _PP_EVAL(_PP_MAP40(f, __VA_ARGS__))
#define _PP_MAP42(f, x, ...) f(x) _PP_EVAL(_PP_MAP41(f, __VA_ARGS__))
#define _PP_MAP43(f, x, ...) f(x) _PP_EVAL(_PP_MAP42(f, __VA_ARGS__))
#define _PP_MAP44(f, x, ...) f(x) _PP_EVAL(_PP_MAP43(f, __VA_ARGS__))
#define _PP_MAP45(f, x, ...) f(x) _PP_EVAL(_PP_MAP44(f, __VA_ARGS__))
#define _PP_MAP46(f, x, ...) f(x) _PP_EVAL(_PP_MAP45(f, __VA_ARGS__))
#define _PP_MAP47(f, x, ...) f(x) _PP_EVAL(_PP_MAP46(f, __VA_ARGS__))
#define _PP_MAP48(f, x, ...) f(x) _PP_EVAL(_PP_MAP47(f, __VA_ARGS__))
#define _PP_MAP49(f, x, ...) f(x) _PP_EVAL(_PP_MAP48(f, __VA_ARGS__))
#define _PP_MAP50(f, x, ...) f(x) _PP_EVAL(_PP_MAP49(f, __VA_ARGS__))
#define _PP_MAP51(f, x, ...) f(x) _PP_EVAL(_PP_MAP50(f, __VA_ARGS__))
#define _PP_MAP52(f, x, ...) f(x) _PP_EVAL(_PP_MAP51(f, __VA_ARGS__))
#define _PP_MAP53(f, x, ...) f(x) _PP_EVAL(_PP_MAP52(f, __VA_ARGS__))
#define _PP_MAP54(f, x, ...) f(x) _PP_EVAL(_PP_MAP53(f, __VA_ARGS__))
#define _PP_MAP55(f, x, ...) f(x) _PP_EVAL(_PP_MAP54(f, __VA_ARGS__))
#define _PP_MAP56(f, x, ...) f(x) _PP_EVAL(_PP_MAP55(f, __VA_ARGS__))
#define _PP_MAP57(f, x, ...) f(x) _PP_EVAL(_PP_MAP56(f, __VA_ARGS__))
#define _PP_MAP58(f, x, ...) f(x) _PP_EVAL(_PP_MAP57(f, __VA_ARGS__))
#define _PP_MAP59(f, x, ...) f(x) _PP_EVAL(_PP_MAP58(f, __VA_ARGS__))
#define _PP_MAP60(f, x, ...) f(x) _PP_EVAL(_PP_MAP59(f, __VA_ARGS__))
#define _PP_MAP61(f, x, ...) f(x) _PP_EVAL(_PP_MAP60(f, __VA_ARGS__))
#define _PP_MAP62(f, x, ...) f(x) _PP_EVAL(_PP_MAP61(f, __VA_ARGS__))
#define _PP_MAP63(f, x, ...) f(x) _PP_EVAL(_PP_MAP62(f, __VA_ARGS__))
#define _PP_MAP64(f, x, ...) f(x) _PP_EVAL(_PP_MAP63(f, __VA_ARGS__))
#define _PP_GET_NTH_ARG( \
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
_11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
_21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
_31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
_41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
_51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
_61, _62, _63, _64, N, ...) N
#define _PP_MAP(f, ...) _PP_EVAL(_PP_EVAL(_PP_GET_NTH_ARG(__VA_ARGS__, \
_PP_MAP64, _PP_MAP63, _PP_MAP62, _PP_MAP61, \
_PP_MAP60, _PP_MAP59, _PP_MAP58, _PP_MAP57, _PP_MAP56, \
_PP_MAP55, _PP_MAP54, _PP_MAP53, _PP_MAP52, _PP_MAP51, \
_PP_MAP50, _PP_MAP49, _PP_MAP48, _PP_MAP47, _PP_MAP46, \
_PP_MAP45, _PP_MAP44, _PP_MAP43, _PP_MAP42, _PP_MAP41, \
_PP_MAP40, _PP_MAP39, _PP_MAP38, _PP_MAP37, _PP_MAP36, \
_PP_MAP35, _PP_MAP34, _PP_MAP33, _PP_MAP32, _PP_MAP31, \
_PP_MAP30, _PP_MAP29, _PP_MAP28, _PP_MAP27, _PP_MAP26, \
_PP_MAP25, _PP_MAP24, _PP_MAP23, _PP_MAP22, _PP_MAP21, \
_PP_MAP20, _PP_MAP19, _PP_MAP18, _PP_MAP17, _PP_MAP16, \
_PP_MAP15, _PP_MAP14, _PP_MAP13, _PP_MAP12, _PP_MAP11, \
_PP_MAP10, _PP_MAP09, _PP_MAP08, _PP_MAP07, _PP_MAP06, \
_PP_MAP05, _PP_MAP04, _PP_MAP03, _PP_MAP02, _PP_MAP01 \
))(f, __VA_ARGS__))
#if REFLECTION_WITH_FIELD_NAME
#define _PP_REFLECTION_FIELD_NAME(x) _PP_STR(_PP_EVAL(x))
#else
#define _PP_REFLECTION_FIELD_NAME(x) ""
#endif
#define _PP_REFLECTION_ALL(x) _PP_EVAL x
#define _PP_REFLECTION_SECOND(x) _PP_EAT x
#define _PP_REFLECTION_FIELD(x) _PP_REFLECTION_ALL(x);
#define _PP_REFLECTION_METHOD2(x) v(this, _PP_REFLECTION_FIELD_NAME(x), x);
#define _PP_REFLECTION_METHOD(x) _PP_REFLECTION_METHOD2(_PP_REFLECTION_SECOND(x))
#define _PP_REFLECTION_VISTOR_METHOD(type, ...) \
template <class Vistor> \
void _reflect(Vistor& v) type { \
_PP_MAP(_PP_REFLECTION_METHOD, __VA_ARGS__) \
}
#define REFLECT(...) \
_PP_MAP(_PP_REFLECTION_FIELD, __VA_ARGS__) \
_PP_REFLECTION_VISTOR_METHOD(_PP_EMPTY, __VA_ARGS__) \
_PP_REFLECTION_VISTOR_METHOD(const, __VA_ARGS__)
// Usage of REFLECT()
#define OBJECT_NAME_METHOD(obj) \
static const char* object_name() { \
return #obj; \
}
struct Demo
{
OBJECT_NAME_METHOD(Demo)
REFLECT(
(int) a,
(int) b,
(std::string) c
)
int d; // DO NOT REFLECT
};
struct Amplifier {
template <class Obj>
void apply(Obj* obj) {
obj->_reflect(*this);
}
template <class Obj, class Field>
void operator() (Obj* /*obj*/, const char* /*name*/, Field& field) {
field *= 100;
}
template <class Obj>
void operator() (Obj* /*obj*/, const char* /*name*/, std::string& field) {
field += "00";
}
};
struct Printer {
template <class Obj>
void print(const Obj& obj) {
obj._reflect(*this);
}
template <class Obj, class Field>
void operator() (Obj* obj, const char* name, const Field& field) {
std::cout << obj->object_name() << "."
<< name << ": " << field << std::endl;
}
};
int main() {
Demo a = {100, 200, "300", 400};
Amplifier amplifier;
amplifier.apply(&a);
Printer printer;
printer.print(a);
}
/*
Output:
Demo.a: 10000
Demo.b: 20000
Demo.c: 30000
*/
BTW, the following code is used for generating all _PP_MAP_? macros (written in JS, so you can run it in web browser).
(function() {
const maxNumOfEle = 64;
const mapNamePrefix = '_PP_MAP';
let codeText = '';
function formatNumWidth(num) {
return ("0" + num).slice(-2);
}
function AddNewLine() {
if (codeText.slice(-1) != ' ') {
codeText += ' ';
}
codeText += '\\\n';
codeText += ' '.repeat(2);
}
codeText += `#define ${mapNamePrefix}${formatNumWidth(1)}(f, x) f(x)\n`;
for (let i = 2; i <= maxNumOfEle; ++i) {
let funId = formatNumWidth(i);
codeText += `#define ${mapNamePrefix}${funId}(f, x, ...) f(x)`;
let nextFunId = formatNumWidth(i - 1);
codeText += ' _PP_EVAL(';
codeText += `${mapNamePrefix}${nextFunId}(f, __VA_ARGS__)`;
codeText += ')';
codeText += '\n';
}
codeText += '\n#define _PP_GET_NTH_ARG(';
AddNewLine();
for (let i = 1; i <= maxNumOfEle; ++i) {
codeText += `_${i}, `;
if ((i % 10) == 0) {
AddNewLine();
}
}
codeText += 'N, ...) N\n';
codeText += `\n#define ${mapNamePrefix}(f, ...) `;
codeText += '_PP_EVAL(_PP_EVAL(_PP_GET_NTH_ARG(__VA_ARGS__,';
AddNewLine();
for (let i = maxNumOfEle; i >= 1; --i) {
let funId = formatNumWidth(i);
codeText += `${mapNamePrefix}${funId}`;
if (i != 1) {
codeText += ', ';
}
if ((i % 5) == 1) {
AddNewLine();
}
}
codeText += '))(f, __VA_ARGS__))\n';
console.log(codeText);
})();
You can't iterate over an object's data members. You can use std::ostream
's stream insertion operator to print individually however:
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';
}
};
And inside main:
int main()
{
A a = {5, 10, "apple sauce"};
std::cout << a;
}
Output:
5
10
apple sauce
Here is a demo.