From 3c41a8a2b762b8843a9f3d0ca62a691c55ae8c6f Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 15:48:51 +0100
Subject: [PATCH 1/7] v3-update

---
 .gitignore                      |   5 +
 CMakeLists.txt                  |  25 +-
 CMakeSettings.json              |  62 ++++
 include/fox/reflexpr.hpp        | 608 ++++++++++++++------------------
 sample/CMakeLists.txt           |   2 +-
 sample/main.cpp                 |  95 ++---
 test/CMakeLists.txt             |  77 ++++
 test/reflexpr_test.cc           | 240 +++++++++++++
 test/reflexpr_test_generator.py |  56 +++
 9 files changed, 756 insertions(+), 414 deletions(-)
 create mode 100644 CMakeSettings.json
 create mode 100644 test/CMakeLists.txt
 create mode 100644 test/reflexpr_test.cc
 create mode 100644 test/reflexpr_test_generator.py

diff --git a/.gitignore b/.gitignore
index a132c2c..60718d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,11 @@ bin/*
 bin-etc/*
 lib/*
 output/*
+out/*
+.vs/*
+
+# Autogenerated
+test/reflexpr_test_types.inl
 
 # Prerequisites
 *.d
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 60cc2d8..354697c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,7 +16,6 @@ if (PROJECT_IS_TOP_LEVEL)
 endif()
     
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
-enable_testing()
 
 include(CheckIPOSupported)
 check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_NOT_SUPPORTED_ERROR LANGUAGES CXX)
@@ -33,13 +32,25 @@ add_subdirectory("include")
 
 add_library(fox::reflexpr ALIAS reflexpr)
 
-option(sample ON)
-# option(test ON)
+option(
+	FOX_REFLEXPR_BUILD_SAMPLES 
+    "If samples are built."
+	ON
+)
 
-if (sample)
+option(
+	FOX_REFLEXPR_BUILD_TESTS
+    "If unit tests are built"
+	ON
+)
+
+option(FOX_REFLEXPR_BUILD_SAMPLES ON)
+option(FOX_REFLEXPR_BUILD_TESTS ON)
+
+if (FOX_REFLEXPR_BUILD_SAMPLES)
 	add_subdirectory("sample")
 endif()
 
-# if (test)
-# 	add_subdirectory("test")
-# endif()
\ No newline at end of file
+if (FOX_REFLEXPR_BUILD_TESTS)
+	add_subdirectory("test")
+endif()
\ No newline at end of file
diff --git a/CMakeSettings.json b/CMakeSettings.json
new file mode 100644
index 0000000..7ae5f66
--- /dev/null
+++ b/CMakeSettings.json
@@ -0,0 +1,62 @@
+{
+  "configurations": [
+    {
+      "name": "x64-Debug",
+      "generator": "Ninja",
+      "configurationType": "Debug",
+      "inheritEnvironments": [ "msvc_x64_x64" ],
+      "buildRoot": "${projectDir}\\out\\build\\${name}",
+      "installRoot": "${projectDir}\\out\\install\\${name}",
+      "cmakeCommandArgs": "",
+      "buildCommandArgs": "",
+      "ctestCommandArgs": ""
+    },
+    {
+      "name": "x64-Clang-Release",
+      "generator": "Ninja",
+      "configurationType": "RelWithDebInfo",
+      "buildRoot": "${projectDir}\\out\\build\\${name}",
+      "installRoot": "${projectDir}\\out\\install\\${name}",
+      "cmakeCommandArgs": "",
+      "buildCommandArgs": "",
+      "ctestCommandArgs": "",
+      "inheritEnvironments": [ "clang_cl_x64_x64" ],
+      "variables": []
+    },
+    {
+      "name": "Mingw64-Release",
+      "generator": "Ninja",
+      "configurationType": "RelWithDebInfo",
+      "buildRoot": "${projectDir}\\out\\build\\${name}",
+      "installRoot": "${projectDir}\\out\\install\\${name}",
+      "cmakeCommandArgs": "",
+      "buildCommandArgs": "-v",
+      "ctestCommandArgs": "",
+      "inheritEnvironments": [ "mingw_64" ],
+      "environments": [
+        {
+          "MINGW64_ROOT": "C:/msys64/mingw64",
+          "BIN_ROOT": "${env.MINGW64_ROOT}/bin",
+          "FLAVOR": "x86_64-w64-mingw32",
+          "TOOLSET_VERSION": "9.1.0",
+          "PATH": "${env.MINGW64_ROOT}/bin;${env.MINGW64_ROOT}/../usr/local/bin;${env.MINGW64_ROOT}/../usr/bin;${env.MINGW64_ROOT}/../bin;${env.PATH}",
+          "INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/tr1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/${env.FLAVOR}",
+          "environment": "mingw_64"
+        }
+      ],
+      "variables": [
+        {
+          "name": "CMAKE_C_COMPILER",
+          "value": "${env.BIN_ROOT}/gcc.exe",
+          "type": "STRING"
+        },
+        {
+          "name": "CMAKE_CXX_COMPILER",
+          "value": "${env.BIN_ROOT}/g++.exe",
+          "type": "STRING"
+        }
+      ],
+      "intelliSenseMode": "linux-gcc-x64"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/include/fox/reflexpr.hpp b/include/fox/reflexpr.hpp
index 8de7b75..5665e09 100644
--- a/include/fox/reflexpr.hpp
+++ b/include/fox/reflexpr.hpp
@@ -1,17 +1,14 @@
-/// This header is part of Ruby Ecosystem distributed under MIT license.
+/// This header is distributed under MIT license.
 ///
 /// Author:			Marcin Poloczek (aka. RedSkittleFox)
 ///	Contact:		RedSkittleFox@gmail.com
 /// Copyright:		Marcin Poloczek
 /// License:		MIT
-/// Version:		2.0.0
+/// Version:		3.0.0
 ///
-/// TODO:
-///		* Improve struct parsing.
-///		* Introduce noreflect keyword
-///		
-#ifndef FOX_REFLEXPR_RUBY_REFLEXPR_H_
-#define FOX_REFLEXPR_RUBY_REFLEXPR_H_
+
+#ifndef FOX_REFLEXPR_REFLEXPR_H_
+#define FOX_REFLEXPR_REFLEXPR_H_
 #pragma once
 
 #include <string>
@@ -25,409 +22,342 @@
 #include <cassert>
 #include <functional>
 #include <type_traits>
+#include <tuple>
+#include <limits>
+#include <utility>
 
 namespace fox::reflexpr
 {
-	/// <summary>
-	/// Satisifes std::is_aggregate
-	/// https://en.cppreference.com/w/cpp/types/is_aggregate
-	/// </summary>
 	template<class T>
 	concept aggregate = std::is_aggregate_v<std::remove_cvref_t<T>>;
-
-	/// <summary>
-	/// Iterates over every member variable of an aggregate 
-	/// </summary>
-	/// <typeparam name="T">Aggregate's Type</typeparam>
-	/// <typeparam name="Pred">Predicate's Type</typeparam>
-	/// <param name="obj">Aggregate to iterate over</param>
-	/// <param name="pred">Predicate that iterates over object. Requires to be invocable with T&, where T is a member type of an aggregate.</param>
-	/// <example>
-	///		void foo()
-	///		{
-	///			std::cout << "For each member variable:\n";
-	///			auto func = []<class T>(T & v)
-	///			{
-	///				std::cout << "Type: " << typeid(T).name() << " Value: " << v << '\n';
-	///			};
-	///			
-	///			aggregate_type at{ 1 , 3.5f, "Foxes are great!" };
-	///			
-	///			reflexpr::for_each_member_variable(at, func);
-	///			std::cout << '\n';
-	///		}
-	/// </example>
-	template<aggregate T, class Pred>
-	void for_each_member_variable(T&& obj, Pred&& pred);
-
-	/// <summary>
-	/// Iterates over every member variable's type of an aggregate
-	/// </summary>
-	/// <typeparam name="T">Aggregate's Type</typeparam>
-	/// <typeparam name="Pred">Predicate's Type</typeparam>
-	/// <param name="pred">Predicate that iterates over object. Invocable as pred.operator()<T>(),
-	/// where T is a member type of an aggregate.</param>
-	/// <example>
-	///		struct functor
-	///		{
-	///			template<class T>
-	///			void operator()() const
-	///			{
-	///				std::cout << "Type: " << typeid(T).name() << '\n';
-	///			};
-	///		};
-	/// 
-	///		void foo()
-	///		{
-	///			std::cout << "For each member type:\n";
-	///			reflexpr::for_each_member_type<aggregate_type, functor>(functor{});
-	///			std::cout << '\n';
-	///		}
-	/// </example>
-	template<std::default_initializable T, class Pred>
-	void for_each_member_type(Pred&& pred);
-
-	/// <summary>
-	/// Iterates over every member variable of an aggregate 
-	/// </summary>
-	/// <typeparam name="T">Reflected Aggregate's Type</typeparam>
-	/// <typeparam name="Pred">Predicate's Type</typeparam>
-	/// <param name="obj">Aggregate to iterate over</param>
-	/// <param name="pred">Predicate that iterates over object. Requires to be invocable with T& and const std::string&, where T is a member type of an aggregate.</param>
-	/// <example>
-	///
-	///		REFLECT(
-	///		struct aggregate_type_reflected
-	///		{
-	///			int a;
-	///			float b;
-	///			std::string str;
-	///		}
-	///		);
-	///		void foo()
-	///		{
-	///			std::cout << "For each member variable reflected:\n";
-	///			auto func = []<class T>(T & v, const std::string & name)
-	///			{
-	///				std::cout << "Name: " << name << " Type: " << typeid(T).name() << " Value: " << v << '\n';
-	///			};
-	///			
-	///			aggregate_type_reflected at{ 1 , 3.5f, "Foxes are great!" };
-	///			
-	///			reflexpr::for_each_reflected_member_variable(at, func);
-	///			std::cout << '\n';
-	///		}
-	/// </example>
-	template<aggregate T, class Pred>
-	void for_each_reflected_member_variable(T& obj, Pred&& pred);
-
-	/// <summary>
-	/// Iterates over every member variable's type of an aggregate
-	/// </summary>
-	/// <typeparam name="T">Reflected Aggregate's Type</typeparam>
-	/// <typeparam name="Pred">Predicate's Type</typeparam>
-	/// <param name="pred">Predicate that iterates over object. Invocable as pred.operator()<T>(const std::string&),
-	/// where T is a member type of an aggregate.</param>
-	/// <example>
-	///		REFLECT(
-	///		struct aggregate_type_reflected
-	///		{
-	///			int a;
-	///			float b;
-	///			std::string str;
-	///		}
-	///		);
-	///
-	///		struct functor_reflected
-	///		{
-	///			template<class T>
-	///			void operator()(const std::string& name) const
-	///			{
-	///				std::cout << "Name: " << name << " Type: " << typeid(T).name() << '\n';
-	///			};
-	///		};
-	///		
-	///		void foo()
-	///		{
-	///			std::cout << "For each member type reflected:\n";
-	///			reflexpr::for_each_reflected_member_type<aggregate_type_reflected, functor_reflected>(functor_reflected{});
-	///			std::cout << '\n';
-	///		}
-	/// </example>
-	template<aggregate T, class Pred>
-	void for_each_reflected_member_type(Pred&& pred);
-
-	/// <summary>
-	/// Calculates compile time number of member variables
-	/// </summary>
-	/// <typeparam name="T">Aggregate Type</typeparam>
-	template<aggregate T>
-	struct member_count;
 }
 
+#define FOX_REFLEXPR_NUM_SUPPORTED_MEMBERS (static_cast<std::size_t>(40))
+
 namespace fox::reflexpr
 {
-	class _reflexpr
+	namespace details
 	{
-		struct _member_variable_t
+		// This is a nasty work-around that makes counting members of aggregates of 
+		// references possible. We iterate over all configurations from N to 0 and check if they
+		// satisfy aggregate initialization. If we reach zero, we check if type is empty, if not, then that means 
+		// there are more members than selected N. We could transfer initial size and increase it, but 
+		// picking a sane value like 30 should satisfy 90% of cases.
+		template<size_t I>
+		struct to_any_type_reference
 		{
-			std::string name;
-			std::type_index type_index = std::type_index(typeid(void));
-			std::ptrdiff_t offset;
+			template<class T>
+			constexpr operator T& ();
 		};
 
-		struct _type_t
-		{
-			std::string name;
-			std::type_index type_index = std::type_index(typeid(void));
-			std::vector<_member_variable_t> member_variables;
-		};
+		template<class T, class, size_t... I>
+		struct member_construct_helper_1 : std::false_type {};
 
-	private:
-		inline static std::unordered_map<std::type_index, _type_t> type_info_;
+		template<class T, size_t... I>
+		struct member_construct_helper_1 < T, std::void_t<decltype(
+			T{ std::declval<to_any_type_reference<I>>()... }
+		) > , I... > : std::true_type {};
 
-	public:
-		template<aggregate T, class Pred>
-		static void for_each_member_variable(T& obj, Pred&& pred)
-		{
-			auto r = type_info_.find(std::type_index(typeid(T)));
-			if (r == std::end(type_info_))
-				throw std::logic_error(std::string("reflexpr: Trying to use not reflected type: ") + typeid(T).name());
+		template<class T, class IndexList>
+		struct member_counter_helper_2;
 
-			const auto& type = r->second;
+		template<class T, size_t... I>
+		struct member_counter_helper_2<T, std::index_sequence<I...>>
+			: member_construct_helper_1<T, void, I...> {};
 
-			auto func = [index = static_cast<size_t>(0llu), &type, &pred]<class U>(U&& v) mutable
-			{
-				std::invoke(pred, std::forward<U>(v), type.member_variables[index].name);
-				++index;
-			};
+		template<class T, size_t Size>
+		struct member_counter_helper_3
+			: member_counter_helper_2<T, std::make_index_sequence<Size>> {};
 
-			::fox::reflexpr::for_each_member_variable(obj, func);
+		template<class T, size_t I>
+		struct member_counter_helper_4
+		{
+			static constexpr size_t value =
+				member_counter_helper_3<T, I>::value ?
+				I : member_counter_helper_4<T, I - 1>::value;
 		};
 
-	private:
-		inline static size_t counter_ = 0;
-
 		template<class T>
-		static void type_register_member_variable_names_(std::string contents) try
+		struct member_counter_helper_4<T, 0>
 		{
-			// get to the inside of the struct
-			contents = std::string(std::find(std::begin(contents), std::end(contents), '{') + 1, std::end(contents) - 1);
-
-			static const std::string member_var_pattern =
-				R"(([a-zA-Z_]+\w*(?=\s*;)))";
-
-			static const std::regex member_var_exp(member_var_pattern,
-				std::regex::ECMAScript | std::regex::optimize);
-
-			static const std::string comment_pattern =
-				R"(((?:\/\*)[\w\s]*(?:\*\/))|((?:\/\/)[\w\s]*\n))";
-
-			static const std::regex comment_exp(comment_pattern,
-				std::regex::ECMAScript | std::regex::optimize);
-
-			static const std::string remove_initializations_pattern
-				= R"((\=\s*\{[\w\s,.=\{\}]*\})|(\s*\{[\w\s,.=\{\}]*\})|(=\s*[\w\s,.=\{\}]*))";
-
-			static const std::regex remove_initializations_exp(remove_initializations_pattern,
-				std::regex::ECMAScript | std::regex::optimize);
-
-			// Remove comments
-			contents = std::regex_replace(contents, comment_exp, "\n");
-			contents = std::regex_replace(contents, remove_initializations_exp, "\n");
-
-			// Find member variables
-			auto match = std::sregex_iterator(
-				std::begin(contents), std::end(contents), member_var_exp);
+			static constexpr size_t value =
+				std::is_empty_v<T> ?
+				0 : std::numeric_limits<size_t>::max();
+		};
+	}
 
-			auto& type = type_info_[std::type_index(typeid(T))];
+	/**
+	 * \brief		Provides access to the number of elements in a tuple as a compile-time constant expression.
+	 * \tparam T	Aggregate type
+	 */
+	template<aggregate T>
+	struct tuple_size :
+		::fox::reflexpr::details::member_counter_helper_4<std::remove_cvref_t<T>, FOX_REFLEXPR_NUM_SUPPORTED_MEMBERS> {};
 
-			for (auto rng = std::ranges::subrange(match, std::sregex_iterator());
-				auto & e : rng)
-			{
-				type.member_variables.push_back(_member_variable_t{ e.str() });
-			}
+	/**
+	 * \brief		Helper variable template. Provides access to the number of elements in a tuple as a compile-time constant expression.
+	 * \tparam T	Aggregate type
+	 */
+	template<class T>
+	static constexpr std::size_t tuple_size_v = tuple_size<T>::value;
 
-			// type.member_variables.shrink_to_fit();
-		}
-		catch (const std::exception& e)
+	namespace details
+	{
+		template<std::size_t I, std::size_t J>
+		struct to_any_type_reference_if_not_j
 		{
-			assert(false && "ruby_reflexpr: Something went horribly wrong.");
+			template<class T>
+			constexpr operator T& ();
 		};
 
-		template<class T>
-		static void type_register_member_variable_type_infos_()
+		template<std::size_t I>
+		struct to_any_type_reference_if_not_j<I, I>
 		{
-			T temp{};
-			auto address = std::bit_cast<ptrdiff_t>(std::addressof(temp));
-			auto& type = type_info_[std::type_index(typeid(T))];
+			template<class T>
+			constexpr operator T ();
+		};
 
-			auto func = [index = static_cast<size_t>(0llu), &type, address]<class U>(U & v) mutable
-			{
-				type.member_variables[index].type_index = std::type_index(typeid(U));
-				type.member_variables[index].offset = std::bit_cast<ptrdiff_t>(std::addressof(v)) - address;
-				++index;
-			};
+		template<class T, class, std::size_t I, std::size_t... Is>
+		struct is_nth_a_reference_helper_1 : std::false_type {};
 
-			::fox::reflexpr::for_each_member_variable(temp, func);
-		}
+		template<class T, std::size_t I, std::size_t... Is>
+		struct is_nth_a_reference_helper_1 < T, std::void_t<decltype(
+			T{ std::declval<to_any_type_reference_if_not_j<I, Is>>()... }
+		) > , I, Is... > : std::true_type {};
 
-	public:
-		template<aggregate  T>
-		static size_t type_register_proxy(std::string contents)
-		{
-			if (type_info_.contains(typeid(T)))
-				return ++counter_;
+		template<class T, std::size_t I, class>
+		struct is_nth_a_reference_helper_2;
 
-			type_register_member_variable_names_<T>(contents);
-			type_register_member_variable_type_infos_<T>();
-
-			return ++counter_;
-		}
-	};
+		template<class T, std::size_t I, std::size_t... Is>
+		struct is_nth_a_reference_helper_2<T, I, std::index_sequence<Is...>> :
+			is_nth_a_reference_helper_1<T, void, I, Is...> {};
 
-	struct _any_type
-	{
-		template<class T>
-		operator T() {}
-	};
+		template<class T, std::size_t I>
+		struct is_nth_a_reference : is_nth_a_reference_helper_2<T, I, std::make_index_sequence<::fox::reflexpr::tuple_size_v<T>>> {};
 
-	template<aggregate T, class... Args>
-	struct _member_count
-	{
-		constexpr static size_t f(int32_t*)
-		{
-			return sizeof...(Args) - 1;
-		}
+		template<class T, class>
+		struct ref_detector_helper_1;
 
-		template<class U = T, class Enabled = decltype(U{ Args{}... }) >
-		constexpr static size_t f(std::nullptr_t)
+		template<class T, std::size_t... Is>
+		struct ref_detector_helper_1<T, std::index_sequence<Is...>>
 		{
-			return _member_count<T, Args..., _any_type>::value;
-		}
-
-		constexpr static auto value = f(nullptr);
-	};
+			static constexpr std::array<bool, ::fox::reflexpr::tuple_size_v<T>> nth_reference{ std::negation_v<is_nth_a_reference<T, Is>>... };
+		};
 
-	template<aggregate T>
-	struct member_count
-	{
-		constexpr static std::size_t value = _member_count<std::remove_cvref_t<T>>::value;
-	};
+		template<class T>
+		struct ref_detector : ref_detector_helper_1<std::remove_cvref_t<T>, std::make_index_sequence<::fox::reflexpr::tuple_size_v<T>>> {};
+	}
 
 #ifdef FOX_REFLEXPR_UNPACK_APPLY
 #pragma message "FOX_REFLEXPR_UNPACK_APPLY macro is internally used by redskittlefox/reflexpr library"
 #undef FOX_REFLEXPR_UNPACK_APPLY
 #endif
 
+#ifdef FOX_REFLEXPR_UNPACK_ALL
+#pragma message "FOX_REFLEXPR_UNPACK_ALL macro is internally used by redskittlefox/reflexpr library"
+#undef FOX_REFLEXPR_UNPACK_ALL
+#endif
+
 #define FOX_REFLEXPR_UNPACK_APPLY(SIZE, ...)			\
 	if constexpr ( size == SIZE )		\
 	{									\
 		auto&& [__VA_ARGS__] = obj;		\
-		apply_pack( std::in_place_index< SIZE >,  __VA_ARGS__ ); \
+		return apply_pack( std::in_place_index< SIZE >, __VA_ARGS__ ); \
 	}
 
-	template<aggregate T, class Pred>
-	void for_each_member_variable(T&& obj, Pred&& pred)
+#define FOX_REFLEXPR_UNPACK_ALL	\
+	FOX_REFLEXPR_UNPACK_APPLY( 1, v0) \
+	FOX_REFLEXPR_UNPACK_APPLY( 2, v0, v1) \
+	FOX_REFLEXPR_UNPACK_APPLY( 3, v0, v1, v2) \
+	FOX_REFLEXPR_UNPACK_APPLY( 4, v0, v1, v2, v3) \
+	FOX_REFLEXPR_UNPACK_APPLY( 5, v0, v1, v2, v3, v4) \
+	FOX_REFLEXPR_UNPACK_APPLY( 6, v0, v1, v2, v3, v4, v5) \
+	FOX_REFLEXPR_UNPACK_APPLY( 7, v0, v1, v2, v3, v4, v5, v6) \
+	FOX_REFLEXPR_UNPACK_APPLY( 8, v0, v1, v2, v3, v4, v5, v6, v7) \
+	FOX_REFLEXPR_UNPACK_APPLY( 9, v0, v1, v2, v3, v4, v5, v6, v7, v8) \
+	FOX_REFLEXPR_UNPACK_APPLY(10, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) \
+	FOX_REFLEXPR_UNPACK_APPLY(11, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) \
+	FOX_REFLEXPR_UNPACK_APPLY(12, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) \
+	FOX_REFLEXPR_UNPACK_APPLY(13, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) \
+	FOX_REFLEXPR_UNPACK_APPLY(14, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) \
+	FOX_REFLEXPR_UNPACK_APPLY(15, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) \
+	FOX_REFLEXPR_UNPACK_APPLY(16, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \
+	FOX_REFLEXPR_UNPACK_APPLY(17, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) \
+	FOX_REFLEXPR_UNPACK_APPLY(18, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) \
+	FOX_REFLEXPR_UNPACK_APPLY(19, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) \
+	FOX_REFLEXPR_UNPACK_APPLY(20, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) \
+	FOX_REFLEXPR_UNPACK_APPLY(21, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) \
+	FOX_REFLEXPR_UNPACK_APPLY(22, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) \
+	FOX_REFLEXPR_UNPACK_APPLY(23, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) \
+	FOX_REFLEXPR_UNPACK_APPLY(24, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) \
+	FOX_REFLEXPR_UNPACK_APPLY(25, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) \
+	FOX_REFLEXPR_UNPACK_APPLY(26, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) \
+	FOX_REFLEXPR_UNPACK_APPLY(27, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) \
+	FOX_REFLEXPR_UNPACK_APPLY(28, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) \
+	FOX_REFLEXPR_UNPACK_APPLY(29, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) \
+	FOX_REFLEXPR_UNPACK_APPLY(30, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) \
+	FOX_REFLEXPR_UNPACK_APPLY(31, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) \
+	FOX_REFLEXPR_UNPACK_APPLY(32, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) \
+	FOX_REFLEXPR_UNPACK_APPLY(33, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) \
+	FOX_REFLEXPR_UNPACK_APPLY(34, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) \
+	FOX_REFLEXPR_UNPACK_APPLY(35, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) \
+	FOX_REFLEXPR_UNPACK_APPLY(36, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) \
+	FOX_REFLEXPR_UNPACK_APPLY(37, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) \
+	FOX_REFLEXPR_UNPACK_APPLY(38, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) \
+	FOX_REFLEXPR_UNPACK_APPLY(39, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) \
+	FOX_REFLEXPR_UNPACK_APPLY(40, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) 
+
+	/**
+	 * \brief	Allows iteration over all members of an aggregate type.
+	 * \tparam T Aggregate type
+	 * \tparam Func Function type
+	 * \param obj Object to iterate over members of.
+	 * \param func Functor invoked for each member.
+	 */
+	template<aggregate T, class Func>
+	constexpr void for_each(T&& obj, Func&& func)
 	{
-		static constexpr size_t size = member_count<T>::value;
+		constexpr size_t size = tuple_size_v<T>;
+		static_assert(size <= FOX_REFLEXPR_NUM_SUPPORTED_MEMBERS, "Unsupported number of struct members");
 
-		auto apply_pack = [&]<std::size_t I, class... Args>(std::in_place_index_t<I>, Args&&... args)
+		auto apply_pack = [&]<std::size_t I, class... Args>(std::in_place_index_t<I>, Args&&... args) -> void
 		{
 			static_assert(I == sizeof...(Args) && "Size and Arguments mismatch.");
-			auto invoke_proxy = [&]<class U>(U && arg) -> void
+			if constexpr(std::is_lvalue_reference_v<decltype(obj)> && std::is_const_v<std::remove_reference_t<decltype(obj)>>)
 			{
-				static_assert(std::is_invocable_v<decltype(pred), decltype(arg)>, "Function is not invokable with type [U]");
-				pred( std::forward<U>(arg) );
-			};
-
-			( invoke_proxy(std::forward<Args>(args) ) , ...);
+				(func(std::as_const(std::forward<Args>(args))), ...);
+			}
+			else
+			{
+				(func(std::forward<Args>(args)), ...);
+			}
 		};
 
-		FOX_REFLEXPR_UNPACK_APPLY(1, v0)
-		FOX_REFLEXPR_UNPACK_APPLY(2, v0, v1)
-		FOX_REFLEXPR_UNPACK_APPLY(3, v0, v1, v2)
-		FOX_REFLEXPR_UNPACK_APPLY(4, v0, v1, v2, v3)
-		FOX_REFLEXPR_UNPACK_APPLY(5, v0, v1, v2, v3, v4)
-		FOX_REFLEXPR_UNPACK_APPLY(6, v0, v1, v2, v3, v4, v5)
-		FOX_REFLEXPR_UNPACK_APPLY(7, v0, v1, v2, v3, v4, v5, v6)
-		FOX_REFLEXPR_UNPACK_APPLY(8, v0, v1, v2, v3, v4, v5, v6, v7)
-		FOX_REFLEXPR_UNPACK_APPLY(9, v0, v1, v2, v3, v4, v5, v6, v7, v8)
-		FOX_REFLEXPR_UNPACK_APPLY(10, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9)
-		FOX_REFLEXPR_UNPACK_APPLY(11, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10)
-		FOX_REFLEXPR_UNPACK_APPLY(12, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
-		FOX_REFLEXPR_UNPACK_APPLY(13, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
-		FOX_REFLEXPR_UNPACK_APPLY(14, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
-		FOX_REFLEXPR_UNPACK_APPLY(15, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
-		FOX_REFLEXPR_UNPACK_APPLY(16, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
-		FOX_REFLEXPR_UNPACK_APPLY(17, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
-		FOX_REFLEXPR_UNPACK_APPLY(18, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
-		FOX_REFLEXPR_UNPACK_APPLY(19, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
-		FOX_REFLEXPR_UNPACK_APPLY(20, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
-		FOX_REFLEXPR_UNPACK_APPLY(21, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
-		FOX_REFLEXPR_UNPACK_APPLY(22, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
-		FOX_REFLEXPR_UNPACK_APPLY(23, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
-		FOX_REFLEXPR_UNPACK_APPLY(24, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
-		FOX_REFLEXPR_UNPACK_APPLY(25, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
-		FOX_REFLEXPR_UNPACK_APPLY(26, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
-		FOX_REFLEXPR_UNPACK_APPLY(27, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
-		FOX_REFLEXPR_UNPACK_APPLY(28, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
-		FOX_REFLEXPR_UNPACK_APPLY(29, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
-		FOX_REFLEXPR_UNPACK_APPLY(30, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
-		FOX_REFLEXPR_UNPACK_APPLY(31, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
-		FOX_REFLEXPR_UNPACK_APPLY(32, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
-		FOX_REFLEXPR_UNPACK_APPLY(33, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
-		FOX_REFLEXPR_UNPACK_APPLY(34, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
-		FOX_REFLEXPR_UNPACK_APPLY(35, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
-		FOX_REFLEXPR_UNPACK_APPLY(36, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
-		FOX_REFLEXPR_UNPACK_APPLY(37, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
-		FOX_REFLEXPR_UNPACK_APPLY(38, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
-		FOX_REFLEXPR_UNPACK_APPLY(39, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
-		FOX_REFLEXPR_UNPACK_APPLY(40, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
-
-		static_assert(size <= 40, "Unsupported number of struct members");
+		FOX_REFLEXPR_UNPACK_ALL
 	};
 
-#undef FOX_REFLEXPR_UNPACK_APPLY
-
-	template<std::default_initializable T, class Pred>
-	void for_each_member_type(Pred&& pred)
+	/**
+	 * \brief Creates a tuple of lvalue references to members of an aggregate.
+	 * \tparam T Aggregate type
+	 * \param obj Object to make a tie of.
+	 * \return A std::tuple object containing lvalue references.
+	 */
+	template<aggregate T>
+	constexpr auto tie(T& obj)
 	{
-		auto proxy = [&pred]<class U>(const U & v) -> void
+		constexpr size_t size = tuple_size_v<T>;
+		static_assert(size <= FOX_REFLEXPR_NUM_SUPPORTED_MEMBERS, "Unsupported number of struct members");
+
+		auto apply_pack = [&]<std::size_t I, class... Args>(std::in_place_index_t<I>, Args&&... args)
 		{
-			pred.template operator() < U > ();
+			static_assert(I == sizeof...(Args) && "Size and Arguments mismatch.");
+			if constexpr(std::is_const_v<T>)
+			{
+				return std::tuple<std::add_lvalue_reference_t<std::add_const_t<std::remove_cvref_t<Args>>>...>{ std::forward<Args>(args)...};
+			}
+			else
+			{
+				return std::tuple<Args&...>{ std::forward<Args>(args)...};
+			}
 		};
 
-		const T* v = nullptr;
-		for_each_member_variable(*v, proxy);
-	};
+		FOX_REFLEXPR_UNPACK_ALL
+	}
 
-	template<aggregate T, class Pred>
-	void for_each_reflected_member_variable(T& obj, Pred&& pred)
+	/**
+	 * \brief Creates a tuple object, deducing the target type from the types of members.
+	 * \tparam T Aggregate type
+	 * \param obj Object to make the tuple from.
+	 * \return A std::tuple object containing the given values.
+	 */
+	template<aggregate T>
+	constexpr auto make_tuple(T&& obj)
 	{
-		_reflexpr::for_each_member_variable(obj, pred);
-	};
+		constexpr size_t size = tuple_size_v<T>;
+		static_assert(size <= FOX_REFLEXPR_NUM_SUPPORTED_MEMBERS, "Unsupported number of struct members");
 
-	template<aggregate T, class Pred>
-	void for_each_reflected_member_type(Pred&& pred)
-	{
-		auto proxy = [&pred]<class U>(const U & v, const std::string & name) -> void
+		auto apply_pack = [&]<std::size_t I, class... Args>(std::in_place_index_t<I>, Args&&... args)
 		{
-			pred.template operator() < U > (name);
+			static_assert(I == sizeof...(Args) && "Size and Arguments mismatch.");
+			using ref_tester = details::ref_detector<T>;
+
+			return [&]<std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				using tuple = std::tuple<Args...>;
+
+				if
+				constexpr ( std::is_const_v<std::remove_reference_t<T>> )
+				{
+					return std::tuple<
+						std::conditional_t < ref_tester::nth_reference[Is],
+						std::add_lvalue_reference_t<std::add_const_t<std::decay_t<std::tuple_element_t<Is, tuple>>>>,
+						std::remove_reference_t<std::decay_t<std::tuple_element_t<Is, tuple>>>
+						> ... >(std::forward<Args>(args)...);
+				}
+				else
+				{
+					return std::tuple<
+						std::conditional_t < ref_tester::nth_reference[Is],
+						std::add_lvalue_reference_t<std::decay_t<std::tuple_element_t<Is, tuple>>>,
+						std::remove_reference_t<std::decay_t<std::tuple_element_t<Is, tuple>>>
+					> ... >(std::forward<Args>(args)...);
+				}
+			}(std::index_sequence_for<Args...>{});
 		};
 
-		const T* v = nullptr;
-		_reflexpr::for_each_member_variable(*v, proxy);
-	};
+		FOX_REFLEXPR_UNPACK_ALL
+	}
 
-}
+#undef FOX_REFLEXPR_UNPACK_APPLY
 
+	/**
+	 * \brief Provides compile-time indexed access to the types of the elements of the aggregate
+	 * \tparam I Index of the element
+	 * \tparam T Aggregate type 
+	 */
+	template<std::size_t I, aggregate T>
+	struct tuple_element
+	{
+		using type = std::tuple_element_t<I, decltype(::fox::reflexpr::make_tuple(std::declval<T>()))>;
+	};
 
-#define _REFLECT_IDENTIFIER_PROXY(X) reflexpr_##X
-#define _REFLECT_IDENTIFIER(X) _REFLECT_IDENTIFIER_PROXY(X)
+	/**
+	 * \brief Helper variable template. Provides compile-time indexed access to the types of the elements of the aggregate
+	 * \tparam I Index of the element
+	 * \tparam T Aggregate type
+	 */
+	template<std::size_t I, aggregate T>
+	using tuple_element_t = typename tuple_element<I, T>::type;
+
+	/**
+	 * \brief Extracts the Ith element from the aggregate.
+	 * \tparam I Index of the element
+	 * \tparam T Aggregate type
+	 * \param obj Object to extract element from
+	 * \return A reference to selected element of obj
+	 */
+	template<std::size_t I, aggregate T>
+	auto get(T& obj) noexcept ->
+	std::add_lvalue_reference_t<fox::reflexpr::tuple_element_t<I, T>>
+		requires ( tuple_size_v<T> > I )
+	{
+		return std::get<I>(fox::reflexpr::tie(obj));
+	}
 
-#define REFLECT(...) typedef __VA_ARGS__ _REFLECT_IDENTIFIER(__LINE__)##_t;\
-	static size_t _REFLECT_IDENTIFIER(__LINE__)##_proxy = \
-		::fox::reflexpr::_reflexpr::type_register_proxy<_REFLECT_IDENTIFIER(__LINE__)##_t>(#__VA_ARGS__);\
+	/**
+	 * \brief Extracts the Ith element from the aggregate.
+	 * \tparam I Index of the element
+	 * \tparam T Aggregate type
+	 * \param obj Object to extract element from
+	 * \return A reference to selected element of obj
+	 */
+	template<std::size_t I, aggregate T>
+	auto get(const T& obj) noexcept ->
+		std::add_lvalue_reference_t<std::add_const_t<std::remove_cvref_t<fox::reflexpr::tuple_element_t<I, T>>>>
+		requires (tuple_size_v<T> > I)
+	{
+		return std::get<I>(fox::reflexpr::tie(obj));
+	}
+}
 
 #endif
\ No newline at end of file
diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt
index d378fb3..4e82384 100644
--- a/sample/CMakeLists.txt
+++ b/sample/CMakeLists.txt
@@ -15,7 +15,7 @@ if(${IPO_SUPPORTED})
     set_target_properties(reflexpr-demo PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
 endif()
 
-if(MSVC)
+if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
     target_compile_options(
         reflexpr-demo
         PRIVATE /WX # all warnings as errors 
diff --git a/sample/main.cpp b/sample/main.cpp
index 4bf6e45..0097133 100644
--- a/sample/main.cpp
+++ b/sample/main.cpp
@@ -2,89 +2,50 @@
 #include <string_view>
 #include <algorithm>
 #include <string>
+#include <array>
 
 #include <fox/reflexpr.hpp>
 
-struct aggregate_type
+struct my_aggregate
 {
 	int a;
 	float b;
-	std::string str;
-};
-
-REFLECT(
-struct aggregate_type_reflected
-{
-	int a;
-	float b;
-	std::string str;
-}
-);
-
-struct functor
-{
-	template<class T>
-	void operator()() const
-	{
-		std::cout << "Type: " << typeid(T).name() << '\n';
-	}
-};
-
-struct functor_reflected
-{
-	template<class T>
-	void operator()(const std::string& name) const
-	{
-		std::cout << "Name: " << name << " Type: " << typeid(T).name() << '\n';
-	}
+	std::string c;
+	int& d;
 };
 
 int main()
 {
-	// DEMO: fox::reflexpr::for_each_member_variable
+	int d = 5;
+	my_aggregate obj
 	{
-		std::cout << "For each member variable:\n";
-		auto func = []<class T>(T & v)
-		{
-			std::cout << "Type: " << typeid(T).name() << " Value: " << v << '\n';
-		};
-
-		aggregate_type at{ 1 , 3.5f, "Foxes are great!" };
+		.a = 1 ,
+		.b = 3.5f,
+		.c = "Foxes are great!",
+		.d = d
+	};
 
-		static_assert(fox::reflexpr::aggregate<aggregate_type>, "sus");
-		fox::reflexpr::for_each_member_variable(at, func);
-		std::cout << '\n';
-	}
-
-	// DEMO: fox::reflexpr::for_each_member_type
-	{
-		std::cout << "For each member type:\n";
+	auto&& [v0, v1, v2, v3] = obj;
 
-		fox::reflexpr::for_each_member_type<aggregate_type, functor>(functor{});
-		std::cout << '\n';
-	}
+	// Get Nth member - fox::reflexpr::get<N>(aggregate)
+	std::cout << fox::reflexpr::get<0>(obj) << '\n'; // prints obj.a 
+	
+	// Iterate over members - fox::reflexpr::for_each(aggregate, func)
+	fox::reflexpr::for_each(obj, [](auto&& v) {std::cout << v << ' '; }), std::cout << '\n';
 
-	// DEMO: fox::reflexpr::for_each_reflected_member_variable
-	{
-		std::cout << "For each member variable reflected:\n";
-		auto func = []<class T>(T & v, const std::string& name)
-		{
-			std::cout << "Name: " << name << " Type: " << typeid(T).name() << " Value: " << v << '\n';
-		};
+	// Create a tuple-tie from members - fox::reflexpr::tie(aggregate)
+	auto tie = fox::reflexpr::tie(obj);
+	std::cout << (std::get<2>(tie) = 2) << '\n';
 
-		aggregate_type_reflected at{ 1 , 3.5f, "Foxes are great!" };
+	// Create a tuple from members - fox::reflexpr::make_tuple(aggregate)
+	auto tuple = fox::reflexpr::make_tuple(obj);
+	std::cout << (std::get<2>(tuple)) << '\n';
 
-		fox::reflexpr::for_each_reflected_member_variable(at, func);
-		std::cout << '\n';
-	}
+	// Tuple size - fox::reflexpr::tuple_size_v<aggregate_type>
+	static_assert(fox::reflexpr::tuple_size_v<my_aggregate> == static_cast<std::size_t>(4));
 
-	// DEMO: fox::reflexpr::for_each_reflected_member_type
-	{
-		std::cout << "For each member type reflected:\n";
+	// Tuple Nth type
+	static_assert(std::is_same_v<fox::reflexpr::tuple_element_t<3, my_aggregate>, int&>);
 
-		fox::reflexpr::for_each_reflected_member_type<aggregate_type_reflected, functor_reflected>(functor_reflected{});
-		std::cout << '\n';
-	}
-	
-	return 1;
+	return 0;
 }
\ No newline at end of file
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..1d07bca
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,77 @@
+cmake_minimum_required(VERSION 3.5)
+
+cmake_policy(PUSH)
+
+enable_testing()
+
+if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
+    cmake_policy(SET CMP0135 NEW)
+endif()
+
+include(FetchContent)
+FetchContent_Declare(
+    googletest
+    URL https://github.com/google/googletest/archive/refs/tags/v1.13.0.zip
+)
+# For Windows: Prevent overriding the parent project's compiler/linker settings
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+FetchContent_MakeAvailable(googletest)
+
+set(sources 
+    "${CMAKE_CURRENT_SOURCE_DIR}/reflexpr_test.cc"
+    "${CMAKE_CURRENT_SOURCE_DIR}/reflexpr_test_generator.py"
+)
+
+source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${sources})
+
+add_executable(
+    reflexpr-test
+    ${sources}
+)
+
+if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
+	target_compile_options(
+        reflexpr-test
+		PRIVATE /W4 
+		PRIVATE /MP 
+		PRIVATE /arch:AVX2
+		PRIVATE /WX
+        PRIVATE /bigobj
+	)
+
+endif()
+
+target_link_libraries(
+    reflexpr-test
+    GTest::gtest_main
+    GTest::gmock_main
+    reflexpr
+)
+
+find_package(Python COMPONENTS Interpreter Development)
+if(NOT ${Python_FOUND})
+    message( FATAL_ERROR "Failed to locate python." )
+endif()
+
+message("${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/reflexpr_test_generator.py")
+
+add_custom_target(
+    reflexpr-test-generator 
+    COMMAND ${Python_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/reflexpr_test_generator.py" "${CMAKE_CURRENT_SOURCE_DIR}"
+    BYPRODUCTS reflexpr_test_types.inl
+    COMMENT "RedSkittleFox::Reflexpr: Generating test types"
+)
+
+add_dependencies(reflexpr-test reflexpr-test-generator)
+
+include(GoogleTest)
+gtest_discover_tests(reflexpr-test)
+
+if (PROJECT_IS_TOP_LEVEL)
+    set_target_properties(gtest_main PROPERTIES FOLDER "vendor")
+    set_target_properties(gtest PROPERTIES FOLDER "vendor")
+    set_target_properties(gmock_main PROPERTIES FOLDER "vendor")
+    set_target_properties(gmock PROPERTIES FOLDER "vendor")
+endif()
+
+cmake_policy(POP)
\ No newline at end of file
diff --git a/test/reflexpr_test.cc b/test/reflexpr_test.cc
new file mode 100644
index 0000000..fb2ae7e
--- /dev/null
+++ b/test/reflexpr_test.cc
@@ -0,0 +1,240 @@
+#include <gtest/gtest.h>
+#include <fox/reflexpr.hpp>
+
+#include <random>
+#include <ranges>
+#include <concepts>
+#include <array>
+#include <utility>
+
+namespace fox::reflexpr
+{
+#include "reflexpr_test_types.inl"
+}
+
+namespace fox::reflexpr
+{
+	template<class Type>
+	class reflexpr_test : public testing::Test {};
+
+	TYPED_TEST_SUITE_P(reflexpr_test);
+
+	TYPED_TEST_P(reflexpr_test, aggregate_concept)
+	{
+		using value_type = TypeParam;
+		EXPECT_EQ(std::is_aggregate_v<value_type>, static_cast<bool>(::fox::reflexpr::aggregate<value_type>));
+	}
+
+	TYPED_TEST_P(reflexpr_test, for_each)
+	{
+		using value_type = TypeParam;
+
+		value_type v;
+
+		auto arr = [&]<std::size_t... Is>(std::index_sequence<Is...>)
+		{
+			return std::array<int, value_type::member_count>{
+				v.template get<Is>()...
+			};
+		}(std::make_index_sequence<value_type::member_count>{});
+		
+		::fox::reflexpr::for_each(v, [&, i = static_cast<std::size_t>(0)]<class T>(T&& e) mutable
+			{
+				EXPECT_TRUE(std::is_lvalue_reference_v<decltype(e)> && std::negation_v<std::is_const<std::remove_reference_t<decltype(e)>>>);
+				EXPECT_EQ(arr[i++], e);
+			});
+
+		::fox::reflexpr::for_each(std::as_const(v), [&, i = static_cast<std::size_t>(0)]<class T>(T&& e) mutable
+		{
+			if constexpr(std::is_lvalue_reference_v<decltype(e)>)
+			{
+				EXPECT_TRUE(std::is_const_v<std::remove_reference_t<decltype(e)>>)
+					<< typeid(T).name();
+			}
+			
+			EXPECT_EQ(arr[i++], e);
+		});
+	}
+
+	TYPED_TEST_P(reflexpr_test, tuple_size)
+	{
+		using value_type = TypeParam;
+		EXPECT_EQ(value_type::member_count, ::fox::reflexpr::tuple_size<value_type>::value);
+		EXPECT_EQ(value_type::member_count, ::fox::reflexpr::tuple_size_v<value_type>);
+	}
+
+	TYPED_TEST_P(reflexpr_test, tuple_element)
+	{
+		using value_type = TypeParam;
+		[]<std::size_t... Is>(std::index_sequence<Is...>)
+		{
+			EXPECT_TRUE(
+				(std::is_same_v<decltype(std::declval<value_type>().template get<Is>()), fox::reflexpr::tuple_element_t<Is, value_type>> && ...)
+			);
+		}(std::make_index_sequence<value_type::member_count>{});
+	}
+
+	TYPED_TEST_P(reflexpr_test, get)
+	{
+		using value_type = TypeParam;
+		{
+			value_type value;
+
+			[&] <std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				([&]<std::size_t I>(std::in_place_index_t<I>)
+				{
+					auto& v0 = fox::reflexpr::get<I>(value);
+					auto v1 = value.template get<I>();
+					EXPECT_TRUE(std::negation_v<std::is_const<std::remove_reference_t<decltype(v0)>>>);
+
+					EXPECT_EQ(v0, v1);
+					v0 *= 2;
+					auto v3 = value.template get<I>();
+					EXPECT_NE(v0, v1);
+					EXPECT_NE(v1, v3);
+					EXPECT_EQ(v0, v3);
+
+				}(std::in_place_index<Is>), ...);
+			}(std::make_index_sequence<value_type::member_count>{});
+		}
+
+		{
+			value_type value;
+
+			[&] <std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				([&]<std::size_t I>(std::in_place_index_t<I>)
+				{
+					auto& v0 = fox::reflexpr::get<Is>(std::as_const(value));
+					auto v1 = value.template get<I>();
+					EXPECT_EQ(v0, v1);
+					EXPECT_TRUE(std::is_const_v<std::remove_reference_t<decltype(v0)>>);
+				}(std::in_place_index<Is>), ...);
+			}(std::make_index_sequence<value_type::member_count>{});
+		}
+	}
+
+	TYPED_TEST_P(reflexpr_test, make_tuple)
+	{
+		using value_type = TypeParam;
+
+		{
+			value_type value;
+			auto tuple = fox::reflexpr::tie(value);
+
+			[&] <std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				([&]<std::size_t I>(std::in_place_index_t<I>)
+				{
+					auto& v0 = fox::reflexpr::get<Is>(value);
+					auto v1 = value.template get<I>();
+					EXPECT_TRUE(std::negation_v<std::is_const<std::remove_reference_t<decltype(v0)>>>);
+
+					EXPECT_EQ(v0, v1);
+					v0 *= 2;
+					auto v3 = value.template get<I>();
+					EXPECT_NE(v0, v1);
+					EXPECT_NE(v1, v3);
+					EXPECT_EQ(v0, v3);
+				}(std::in_place_index<Is>), ...);
+			}(std::make_index_sequence<value_type::member_count>{});
+		}
+
+		{
+			value_type value;
+			auto tuple = fox::reflexpr::tie(std::as_const(value));
+
+			[&] <std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				([&]<std::size_t I>(std::in_place_index_t<I>)
+				{
+					auto& v0 = std::get<I>(tuple);
+					auto v1 = value.template get<I>();
+					EXPECT_EQ(v0, v1);
+					EXPECT_TRUE(std::is_const_v<std::remove_reference_t<decltype(v0)>>)
+						<< typeid(tuple).name();
+				}(std::in_place_index<Is>), ...);
+			}(std::make_index_sequence<value_type::member_count>{});
+		}
+	}
+
+	TYPED_TEST_P(reflexpr_test, tie)
+	{
+		using value_type = TypeParam;
+
+		using value_type = TypeParam;
+
+		{
+			value_type value;
+			auto tuple = fox::reflexpr::make_tuple(value);
+			using tuple_type = std::remove_cvref_t<decltype(tuple)>;
+			[&] <std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				([&]<std::size_t I>(std::in_place_index_t<I>)
+				{
+					auto& v0 = std::get<Is>(tuple);
+					auto v1 = value.template get<I>();
+					EXPECT_TRUE(std::negation_v<std::is_const<std::remove_reference_t<decltype(v0)>>>);
+
+					if
+						constexpr (
+							std::is_same_v<
+							std::tuple_element_t<I, tuple_type>,
+							decltype(std::declval<value_type>().template get<I>())
+							> &&
+							std::is_lvalue_reference_v<std::tuple_element_t<I, tuple_type>>
+							)
+					{
+						EXPECT_EQ(v0, v1);
+						v0 *= 2;
+						auto v3 = value.template get<I>();
+						EXPECT_NE(v0, v1);
+						EXPECT_NE(v1, v3);
+						EXPECT_EQ(v0, v3);
+					}
+				}(std::in_place_index<Is>), ...);
+			}(std::make_index_sequence<value_type::member_count>{});
+		}
+
+		{
+			value_type value;
+			auto tuple = fox::reflexpr::make_tuple(std::as_const(value));
+			using tuple_type = std::remove_reference_t<decltype(tuple)>;
+			[&] <std::size_t... Is>(std::index_sequence<Is...>)
+			{
+				([&]<std::size_t I>(std::in_place_index_t<I>)
+				{
+					auto& v0 = std::get<I>(tuple);
+					auto v1 = value.template get<I>();
+					EXPECT_EQ(v0, v1);
+					if constexpr (std::is_lvalue_reference_v<std::tuple_element_t<I, tuple_type>>)
+					{
+						EXPECT_TRUE(std::is_const_v<std::remove_reference_t<decltype(v0)>>);
+					}
+				}(std::in_place_index<Is>), ...);
+			}(std::make_index_sequence<value_type::member_count>{});
+		}
+	}
+
+	struct test_aggregate_test
+	{
+		static constexpr std::size_t member_count = 2;
+
+		template<std::size_t I>
+		auto get() -> decltype(auto) requires (I < member_count)
+		{
+			if constexpr (I == 0)
+				return a;
+			if constexpr (I == 1)
+				return b;
+		}
+
+		static inline int s_a = 1;
+		int& a = s_a;
+		int b = 2;
+	};
+
+	REGISTER_TYPED_TEST_SUITE_P(reflexpr_test, aggregate_concept, for_each, tuple_size, tuple_element, get, make_tuple, tie);
+	INSTANTIATE_TYPED_TEST_SUITE_P(fundamental, reflexpr_test, types);
+}
\ No newline at end of file
diff --git a/test/reflexpr_test_generator.py b/test/reflexpr_test_generator.py
new file mode 100644
index 0000000..c203c78
--- /dev/null
+++ b/test/reflexpr_test_generator.py
@@ -0,0 +1,56 @@
+import os
+import sys
+
+num_supported_members : int = 40
+out = ""
+
+for i in range(1, num_supported_members):
+	out_class = """
+struct test_aggregate_%d
+{
+	static constexpr std::size_t member_count = %d;
+	
+	template<std::size_t I>
+	auto get() -> decltype(auto) requires (I < member_count)
+	{
+""" % (i, i)
+    
+	for j in range(1, i + 1):
+		out_class = out_class + """
+		if constexpr (I == %d)
+			return v%d;
+""" % (j - 1, j)
+		
+	out_class = out_class + """
+	}
+	"""
+	
+	for j in range(1, i + 1):
+		if j % 2 == 0:
+			out_class = out_class + """
+		int v%d = %d;""" % (j, j)
+		else:
+			out_class = out_class + """
+		static inline int s_v%d = %d;
+		int& v%d = s_v%d;""" % (j, j, j, j)
+
+	out_class = out_class + """
+};
+"""
+	out = out + out_class
+	
+out = out + f"""
+using types = testing::Types<
+	"""
+	
+for i in range(1, num_supported_members):
+	out = out + f"""test_aggregate_{i}"""
+	if i + 1 != num_supported_members:
+		out += ", "
+
+out = out + """>;"""
+
+
+f = open(f"{sys.argv[1]}/reflexpr_test_types.inl", "w")
+f.write(out)
+f.close()
\ No newline at end of file

From 89c9404c41bceedbe50c33509fb82b3d4c5a2119 Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 15:54:02 +0100
Subject: [PATCH 2/7] workflow and readme update

---
 .github/workflows/cmake-msvc-build.yml     |  39 --------
 .github/workflows/cmake-multi-platform.yml |  75 +++++++++++++++
 README.md                                  | 102 ++++++---------------
 sample/main.cpp                            |   4 -
 4 files changed, 102 insertions(+), 118 deletions(-)
 delete mode 100644 .github/workflows/cmake-msvc-build.yml
 create mode 100644 .github/workflows/cmake-multi-platform.yml

diff --git a/.github/workflows/cmake-msvc-build.yml b/.github/workflows/cmake-msvc-build.yml
deleted file mode 100644
index 1704bd8..0000000
--- a/.github/workflows/cmake-msvc-build.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage.
-# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml
-name: CMake MSVC Build and Test
-
-on:
-  push:
-    branches: [ "main" ]
-  pull_request:
-    branches: [ "main" ]
-
-env:
-  # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
-  BUILD_TYPE: Release
-
-jobs:
-  build:
-    # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
-    # You can convert this to a matrix build if you need cross-platform coverage.
-    # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
-    runs-on: windows-latest
-
-    steps:
-    - uses: actions/checkout@v3
-
-    - name: Configure CMake
-      # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
-      # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
-      run: cmake -Dsample=ON -Dtest=ON -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
-
-    - name: Build
-      # Build your program with the given configuration
-      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
-
-    # Currently no tests
-    # - name: Test
-      # working-directory: ${{github.workspace}}/build
-      # Execute tests defined by the CMake configuration.
-      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
-      # run: ctest -C ${{env.BUILD_TYPE}}
diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml
new file mode 100644
index 0000000..e995f98
--- /dev/null
+++ b/.github/workflows/cmake-multi-platform.yml
@@ -0,0 +1,75 @@
+# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
+# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
+name: CMake on multiple platforms
+
+on:
+  push:
+    branches: [ "main" ]
+  pull_request:
+    branches: [ "main" ]
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
+      fail-fast: false
+
+      # Set up a matrix to run the following 3 configurations:
+      # 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
+      # 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
+      # 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
+      #
+      # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
+      matrix:
+        os: [ubuntu-latest, windows-latest]
+        build_type: [Release]
+        c_compiler: [gcc, clang, cl]
+        include:
+          - os: windows-latest
+            c_compiler: cl
+            cpp_compiler: cl
+          - os: ubuntu-latest
+            c_compiler: gcc
+            cpp_compiler: g++
+          - os: ubuntu-latest
+            c_compiler: clang
+            cpp_compiler: clang++
+        exclude:
+          - os: windows-latest
+            c_compiler: gcc
+          - os: windows-latest
+            c_compiler: clang
+          - os: ubuntu-latest
+            c_compiler: cl
+
+    steps:
+    - uses: actions/checkout@v3
+
+    - name: Set reusable strings
+      # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
+      id: strings
+      shell: bash
+      run: |
+        echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
+
+    - name: Configure CMake
+      # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
+      # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
+      run: >
+        cmake -B ${{ steps.strings.outputs.build-output-dir }}
+        -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
+        -DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
+        -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
+        -S ${{ github.workspace }}
+
+    - name: Build
+      # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
+      run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
+
+    - name: Test
+      working-directory: ${{ steps.strings.outputs.build-output-dir }}
+      # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
+      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
+      run: ctest --build-config ${{ matrix.build_type }}
diff --git a/README.md b/README.md
index e97c18d..c06bd03 100644
--- a/README.md
+++ b/README.md
@@ -5,102 +5,54 @@ is a c++20 compile and runtime aggregate reflections header only library. It all
 
 # Example Usage
 ```cpp
-// demo.cpp
 #include <iostream>
-#include <string_view>
-#include <algorithm>
 #include <string>
-
 #include <fox/reflexpr.hpp>
 
-struct aggregate_type
-{
-	int a;
-	float b;
-	std::string str;
-};
-
-REFLECT(
-struct aggregate_type_reflected
+struct my_aggregate
 {
 	int a;
 	float b;
-	std::string str;
-}
-);
-
-struct functor
-{
-	template<class T>
-	void operator()() const
-	{
-		std::cout << "Type: " << typeid(T).name() << '\n';
-	}
-};
-
-struct functor_reflected
-{
-	template<class T>
-	void operator()(const std::string& name) const
-	{
-		std::cout << "Name: " << name << " Type: " << typeid(T).name() << '\n';
-	}
+	std::string c;
+	int& d;
 };
 
 int main()
 {
-	// DEMO: fox::reflexpr::for_each_member_variable
+	int d = 5;
+	my_aggregate obj
 	{
-		std::cout << "For each member variable:\n";
-		auto func = []<class T>(T & v)
-		{
-			std::cout << "Type: " << typeid(T).name() << " Value: " << v << '\n';
-		};
+		.a = 1 ,
+		.b = 3.5f,
+		.c = "Foxes are great!",
+		.d = d
+	};
 
-		aggregate_type at{ 1 , 3.5f, "Foxes are great!" };
-
-		static_assert(fox::reflexpr::aggregate<aggregate_type>, "sus");
-		fox::reflexpr::for_each_member_variable(at, func);
-		std::cout << '\n';
-	}
-
-	// DEMO: fox::reflexpr::for_each_member_type
-	{
-		std::cout << "For each member type:\n";
+	auto&& [v0, v1, v2, v3] = obj;
 
-		fox::reflexpr::for_each_member_type<aggregate_type, functor>(functor{});
-		std::cout << '\n';
-	}
+	// Get Nth member - fox::reflexpr::get<N>(aggregate)
+	std::cout << fox::reflexpr::get<0>(obj) << '\n'; // prints obj.a 
+	
+	// Iterate over members - fox::reflexpr::for_each(aggregate, func)
+	fox::reflexpr::for_each(obj, [](auto&& v) {std::cout << v << ' '; }), std::cout << '\n';
 
-	// DEMO: fox::reflexpr::for_each_reflected_member_variable
-	{
-		std::cout << "For each member variable reflected:\n";
-		auto func = []<class T>(T & v, const std::string& name)
-		{
-			std::cout << "Name: " << name << " Type: " << typeid(T).name() << " Value: " << v << '\n';
-		};
+	// Create a tuple-tie from members - fox::reflexpr::tie(aggregate)
+	auto tie = fox::reflexpr::tie(obj);
+	std::cout << (std::get<2>(tie) = 2) << '\n';
 
-		aggregate_type_reflected at{ 1 , 3.5f, "Foxes are great!" };
+	// Create a tuple from members - fox::reflexpr::make_tuple(aggregate)
+	auto tuple = fox::reflexpr::make_tuple(obj);
+	std::cout << (std::get<2>(tuple)) << '\n';
 
-		fox::reflexpr::for_each_reflected_member_variable(at, func);
-		std::cout << '\n';
-	}
+	// Tuple size - fox::reflexpr::tuple_size_v<aggregate_type>
+	static_assert(fox::reflexpr::tuple_size_v<my_aggregate> == static_cast<std::size_t>(4));
 
-	// DEMO: fox::reflexpr::for_each_reflected_member_type
-	{
-		std::cout << "For each member type reflected:\n";
+	// Tuple Nth type
+	static_assert(std::is_same_v<fox::reflexpr::tuple_element_t<3, my_aggregate>, int&>);
 
-		fox::reflexpr::for_each_reflected_member_type<aggregate_type_reflected, functor_reflected>(functor_reflected{});
-		std::cout << '\n';
-	}
-	
-	return 1;
+	return 0;
 }
 ```
 
-# Planned Improvements
-*	Improving member variable names parsing.
-*	Write unit tests.
-	
 # Limitation
 Right now it supports only up to 40 member variables and introduces small runtime overhead when registering member variable names.
diff --git a/sample/main.cpp b/sample/main.cpp
index 0097133..0360d60 100644
--- a/sample/main.cpp
+++ b/sample/main.cpp
@@ -1,9 +1,5 @@
 #include <iostream>
-#include <string_view>
-#include <algorithm>
 #include <string>
-#include <array>
-
 #include <fox/reflexpr.hpp>
 
 struct my_aggregate

From e1453baeff296dfd7416a643149bd509a4353bc5 Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 16:03:08 +0100
Subject: [PATCH 3/7] fixed cmake for msvc

---
 include/fox/reflexpr.hpp | 1 +
 test/CMakeLists.txt      | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/fox/reflexpr.hpp b/include/fox/reflexpr.hpp
index 5665e09..da3541a 100644
--- a/include/fox/reflexpr.hpp
+++ b/include/fox/reflexpr.hpp
@@ -11,6 +11,7 @@
 #define FOX_REFLEXPR_REFLEXPR_H_
 #pragma once
 
+#include <array>
 #include <string>
 #include <vector>
 #include <unordered_map>
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 1d07bca..761dd64 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -29,7 +29,7 @@ add_executable(
     ${sources}
 )
 
-if(${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC")
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
 	target_compile_options(
         reflexpr-test
 		PRIVATE /W4 

From e681bf8dbcc5b5ba7d5d802b1cc35d2b8ebb11c6 Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 16:06:17 +0100
Subject: [PATCH 4/7] changed cmake to c++20

---
 CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 354697c..25607a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@ if (PROJECT_IS_TOP_LEVEL)
     set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin-etc")
     set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin")
     
-    set(CMAKE_CXX_STANDARD 23)
+    set(CMAKE_CXX_STANDARD 20)
     set(CMAKE_CXX_STANDARD_REQUIRED)
 endif()
     

From f334e79dccaa5931d4a4582c03a1b3b3885f44fc Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 16:12:16 +0100
Subject: [PATCH 5/7] disable clang build, actions fail with default clang and
 C++20

---
 .github/workflows/cmake-multi-platform.yml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml
index e995f98..07f3415 100644
--- a/.github/workflows/cmake-multi-platform.yml
+++ b/.github/workflows/cmake-multi-platform.yml
@@ -33,14 +33,14 @@ jobs:
           - os: ubuntu-latest
             c_compiler: gcc
             cpp_compiler: g++
-          - os: ubuntu-latest
-            c_compiler: clang
-            cpp_compiler: clang++
+#           - os: ubuntu-latest
+            # c_compiler: clang
+            # cpp_compiler: clang++
         exclude:
           - os: windows-latest
             c_compiler: gcc
-          - os: windows-latest
-            c_compiler: clang
+          # - os: windows-latest
+#             c_compiler: clang
           - os: ubuntu-latest
             c_compiler: cl
 

From 73c99ad65567043cdafa91fee96669c8ebc55a8d Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 16:13:49 +0100
Subject: [PATCH 6/7] fixed typo

---
 .github/workflows/cmake-multi-platform.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml
index 07f3415..2a45256 100644
--- a/.github/workflows/cmake-multi-platform.yml
+++ b/.github/workflows/cmake-multi-platform.yml
@@ -25,7 +25,7 @@ jobs:
       matrix:
         os: [ubuntu-latest, windows-latest]
         build_type: [Release]
-        c_compiler: [gcc, clang, cl]
+        c_compiler: [gcc, cl] # clang,
         include:
           - os: windows-latest
             c_compiler: cl

From 88096a43593a2baa8c2e2098ce7a9cb9b8d82798 Mon Sep 17 00:00:00 2001
From: RedSkittleFox <RedSkittleFox@gmail.com>
Date: Wed, 17 Jan 2024 16:15:03 +0100
Subject: [PATCH 7/7] update readme

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index c06bd03..b911674 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![CMake MSVC Build and Test](https://github.com/RedSkittleFox/reflexpr/actions/workflows/cmake-msvc-build.yml/badge.svg)](https://github.com/RedSkittleFox/reflexpr/actions/workflows/cmake-msvc-build.yml)
+[![CMake on multiple platforms](https://github.com/RedSkittleFox/reflexpr/actions/workflows/cmake-multi-platform.yml/badge.svg)](https://github.com/RedSkittleFox/reflexpr/actions/workflows/cmake-multi-platform.yml)
 
 # reflexpr
 is a c++20 compile and runtime aggregate reflections header only library. It allows you to iterate over aggregate type's member variables.