#include <iostream>
#include <string>

namespace memenum
{
    template <int Counter>
	struct member_iterator : member_iterator<Counter - 1> { static int const value = Counter; };
	template <>
	struct member_iterator<0> { static int const value = 0; };

	template <class This, class Op>
	void call_for_members(This*, member_iterator<__COUNTER__>, Op const&) { }

	template <class T>
	struct member_wrapper
	{
		T value;
		member_wrapper(T const &v) : value(v) { }
	};

	#define DEFINE_MEMBER(type, memname, ...) \
		struct _##memname##_type : ::memenum::member_wrapper<type> \
		{ \
			static int const counter = __COUNTER__; \
			_##memname##_type() : ::memenum::member_wrapper<type>(__VA_ARGS__) { } \
			char const* name() const { return #memname; } \
		} memname; \
		template <class This, class Op> \
		friend void call_for_members(This *self, ::memenum::member_iterator<_##memname##_type::counter> i, Op const &op, typename This::_##memname##_type* = nullptr) \
		{ \
			call_for_members(self, ::memenum::member_iterator<_##memname##_type::counter - 1>(), op); \
			op(self->memname); \
		}

	#define MAKE_MEMBER_ITERATOR() ::memenum::member_iterator<__COUNTER__>()

} // namespace

namespace test
{
	
	struct foo
	{
		DEFINE_MEMBER(int, a, 2);
		DEFINE_MEMBER(float, b, 2.5f);

	public:
		struct Printer
		{
			template <class T>
			void operator ()(T &member) const
			{
				std::cout << member.name() << " = " << member.value << std::endl;
			}
		};
		void print() const
		{
			call_for_members(this, MAKE_MEMBER_ITERATOR(), Printer());
		}

		struct Multiplier
		{
			int factor;

			template <class T>
			void operator ()(T &member) const
			{
				member.value *= factor;
			}
		};

		void multiply(int factor)
		{
			Multiplier multi = { factor };
			call_for_members(this, MAKE_MEMBER_ITERATOR(), multi);
		}
	};

	struct bar
	{
		DEFINE_MEMBER(char, c, 'd');
		DEFINE_MEMBER(std::string, d, "hello world");

	public:
		struct Printer
		{
			template <class T>
			void operator ()(T &member) const
			{
				std::cout << member.name() << " = " << member.value << std::endl;
			}
		};
		void print() const
		{
			call_for_members(this, MAKE_MEMBER_ITERATOR(), Printer());
		}
	};

} // namespace

int main()
{
	test::foo test1;
	test1.print();
	test1.multiply(5);
	test1.print();

	const test::bar test2;
	test2.print();
}
