From d35b6f047ce4e99246b7dd38f2ea0d549e18c1ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Wed, 24 May 2017 01:32:53 +0200
Subject: [PATCH 01/11] Range interface

---
 hdr/sqlite_modern_cpp.h | 86 ++++++++++++++++++++++++++++++++++++++++-
 tests/readme_example.cc | 15 +++++++
 2 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index 0d328470..d460db94 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -81,6 +81,7 @@ namespace sqlite {
 		static void iterate(Tuple&, database_binder&) {}
 	};
 
+	class row_iterator;
 	class database_binder {
 
 	public:
@@ -128,6 +129,8 @@ namespace sqlite {
 			execution_started = state; 
 		}
 		bool used() const { return execution_started; }
+		row_iterator begin();
+		row_iterator end();
 
 	private:
 		std::shared_ptr<sqlite3> _db;
@@ -312,7 +315,88 @@ namespace sqlite {
 				binder<traits::arity>::run(*this, func);
 			});
 		}
+		friend class row_iterator;
 	};
+	class row_iterator {
+	public:
+		class value_type {
+		public:
+			value_type(database_binder *_binder): _binder(_binder) {};
+			template<class T>
+			value_type &operator >>(T &result) {
+				get_col_from_db(*_binder, next_index++, result);
+				return *this;
+			}
+			template<class ...Types>
+			value_type &operator >>(std::tuple<Types...>& values) {
+				assert(!next_index);
+				tuple_iterate<std::tuple<Types...>>::iterate(values, *_binder);
+				next_index = sizeof...(Types) + 1;
+				return *this;
+			}
+			explicit operator bool() {
+				return sqlite3_column_count(_binder->_stmt.get()) >= next_index;
+			}
+			template<class Type>
+			operator Type() {
+				Type value;
+				*this >> value;
+				return value;
+			}
+		private:
+			database_binder *_binder;
+			int next_index = 0;
+		};
+		using difference_type = std::ptrdiff_t;
+		using pointer = value_type*;
+		using reference = value_type&;
+		using iterator_category = std::input_iterator_tag;
+
+		row_iterator() = default;
+		explicit row_iterator(database_binder &binder): _binder(&binder) {
+			_binder->_start_execute();
+			++*this;
+		}
+
+		reference operator*() const { return value;}
+		pointer operator->() const { return std::addressof(**this); }
+		row_iterator &operator++() {
+			switch(int result = sqlite3_step(_binder->_stmt.get())) {
+				case SQLITE_ROW:
+					value = {_binder};
+					/* tuple_iterate<value_type>::iterate(_value, *_binder); */
+					break;
+				case SQLITE_DONE:
+					_binder = nullptr;
+					break;
+				default:
+					_binder = nullptr;
+					exceptions::throw_sqlite_error(result, _binder->sql());
+			}
+			return *this;
+		}
+
+		// Not well-defined
+		row_iterator operator++(int);
+		friend inline bool operator ==(const row_iterator &a, const row_iterator &b) {
+			return a._binder == b._binder;
+		}
+		friend inline bool operator !=(const row_iterator &a, const row_iterator &b) {
+			return !(a==b);
+		}
+
+	private:
+		database_binder *_binder = nullptr;
+		mutable value_type value{_binder}; // mutable, because `changing` the value is just reading it
+	};
+
+	inline row_iterator database_binder::begin() {
+		return row_iterator(*this);
+	}
+
+	inline row_iterator database_binder::end() {
+		return row_iterator();
+	}
 
 	namespace sql_function_binder {
 		template<
@@ -913,7 +997,7 @@ namespace sqlite {
 	void inline operator++(database_binder& db, int) { db.execute(); }
 
 	// Convert the rValue binder to a reference and call first op<<, its needed for the call that creates the binder (be carefull of recursion here!)
-	template<typename T> database_binder&& operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
+	template<typename T> database_binder operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
 
 	namespace sql_function_binder {
 		template<class T>
diff --git a/tests/readme_example.cc b/tests/readme_example.cc
index e903a85f..851587a9 100644
--- a/tests/readme_example.cc
+++ b/tests/readme_example.cc
@@ -49,6 +49,21 @@ int main() {
 					exit(EXIT_FAILURE);
 				cout << _age << ' ' << _name << ' ' << _weight << endl;
 		};
+		for(auto &&row : db << "select age,name,weight from user where age > ? ;" << 21) {
+			int _age;
+			string _name;
+			double _weight;
+			row >> _age >> _name >> _weight;
+			if(_age != age || _name != name) 
+				exit(EXIT_FAILURE);
+			cout << _age << ' ' << _name << ' ' << _weight << endl;
+		}
+
+		for(std::tuple<int, string, double> row : db << "select age,name,weight from user where age > ? ;" << 21) {
+			if(std::get<int>(row) != age || std::get<string>(row) != name) 
+				exit(EXIT_FAILURE);
+			cout << std::get<int>(row) << ' ' << std::get<string>(row) << ' ' << std::get<double>(row) << endl;
+		}
 
 		// selects the count(*) from user table
 		// note that you can extract a single culumn single row result only to : int,long,long,float,double,string,u16string

From 3d7e040b4cb548e0c5c974ae9a178257cf8e389d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Wed, 24 May 2017 12:20:13 +0200
Subject: [PATCH 02/11] Reimplement execute primitives with iterators

---
 hdr/sqlite_modern_cpp.h | 47 +++++++++++++++--------------------------
 1 file changed, 17 insertions(+), 30 deletions(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index d460db94..610e3ce5 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -154,37 +154,9 @@ namespace sqlite {
 			used(true);
 		}
 
-		void _extract(std::function<void(void)> call_back) {
-			int hresult;
-			_start_execute();
-
-			while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
-				call_back();
-			}
+		void _extract(std::function<void(void)> call_back);
 
-			if(hresult != SQLITE_DONE) {
-				errors::throw_sqlite_error(hresult, sql());
-			}
-		}
-
-		void _extract_single_value(std::function<void(void)> call_back) {
-			int hresult;
-			_start_execute();
-
-			if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
-				call_back();
-			} else if(hresult == SQLITE_DONE) {
-				throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
-			}
-
-			if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
-				throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW);
-			}
-
-			if(hresult != SQLITE_DONE) {
-				errors::throw_sqlite_error(hresult, sql());
-			}
-		}
+		void _extract_single_value(std::function<void(void)> call_back);
 
 #ifdef _MSC_VER
 		sqlite3_stmt* _prepare(const std::u16string& sql) {
@@ -397,6 +369,21 @@ namespace sqlite {
 	inline row_iterator database_binder::end() {
 		return row_iterator();
 	}
+	void database_binder::_extract(std::function<void(void)> call_back) {
+		for(auto &&row[[maybe_unused]] : *this)
+			call_back();
+	}
+
+	void database_binder::_extract_single_value(std::function<void(void)> call_back) {
+		auto iter = begin();
+		if(iter == end())
+			throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
+
+		call_back();
+
+		if(++iter != end())
+			throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW);
+	}
 
 	namespace sql_function_binder {
 		template<

From a5f9f6e28932ada7f8d9f53fd4392588f14bb387 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Wed, 24 May 2017 13:48:45 +0200
Subject: [PATCH 03/11] Fix bugs

---
 hdr/sqlite_modern_cpp.h | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index 610e3ce5..ca89125b 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -295,10 +295,16 @@ namespace sqlite {
 		public:
 			value_type(database_binder *_binder): _binder(_binder) {};
 			template<class T>
-			value_type &operator >>(T &result) {
+			typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
 				get_col_from_db(*_binder, next_index++, result);
 				return *this;
 			}
+			template<class T, typename = typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type>
+			operator T() {
+				T result;
+				*this >> result;
+				return result;
+			}
 			template<class ...Types>
 			value_type &operator >>(std::tuple<Types...>& values) {
 				assert(!next_index);
@@ -306,15 +312,15 @@ namespace sqlite {
 				next_index = sizeof...(Types) + 1;
 				return *this;
 			}
-			explicit operator bool() {
-				return sqlite3_column_count(_binder->_stmt.get()) >= next_index;
-			}
-			template<class Type>
-			operator Type() {
-				Type value;
+			template<class ...Types>
+			operator std::tuple<Types...>() {
+				std::tuple<Types...> value;
 				*this >> value;
 				return value;
 			}
+			explicit operator bool() {
+				return sqlite3_column_count(_binder->_stmt.get()) >= next_index;
+			}
 		private:
 			database_binder *_binder;
 			int next_index = 0;
@@ -342,7 +348,6 @@ namespace sqlite {
 					_binder = nullptr;
 					break;
 				default:
-					_binder = nullptr;
 					exceptions::throw_sqlite_error(result, _binder->sql());
 			}
 			return *this;

From 5bbe246ae25512f7d7bd6d85ff602bb39dc2f1ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Wed, 24 May 2017 14:49:31 +0200
Subject: [PATCH 04/11] Implement all executions with iterators

---
 hdr/sqlite_modern_cpp.h                       | 191 +++++++++---------
 .../utility/function_traits.h                 |   3 +-
 2 files changed, 101 insertions(+), 93 deletions(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index ca89125b..ee116555 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -95,16 +95,7 @@ namespace sqlite {
 			_stmt(std::move(other._stmt)),
 			_inx(other._inx), execution_started(other.execution_started) { }
 
-		void execute() {
-			_start_execute();
-			int hresult;
-
-			while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {}
-
-			if(hresult != SQLITE_DONE) {
-				errors::throw_sqlite_error(hresult, sql());
-			}
-		}
+		void execute();
 		
 		std::string sql() {
 #if SQLITE_VERSION_NUMBER >= 3014000
@@ -148,15 +139,6 @@ namespace sqlite {
 			}
 			return ++_inx;
 		}
-		void _start_execute() {
-			_next_index();
-			_inx = 0;
-			used(true);
-		}
-
-		void _extract(std::function<void(void)> call_back);
-
-		void _extract_single_value(std::function<void(void)> call_back);
 
 #ifdef _MSC_VER
 		sqlite3_stmt* _prepare(const std::u16string& sql) {
@@ -179,31 +161,6 @@ namespace sqlite {
 			return tmp;
 		}
 
-		template <typename Type>
-		struct is_sqlite_value : public std::integral_constant<
-			bool,
-			std::is_floating_point<Type>::value
-			|| std::is_integral<Type>::value
-			|| std::is_same<std::string, Type>::value
-			|| std::is_same<std::u16string, Type>::value
-			|| std::is_same<sqlite_int64, Type>::value
-		> { };
-		template <typename Type, typename Allocator>
-		struct is_sqlite_value< std::vector<Type, Allocator> > : public std::integral_constant<
-			bool,
-			std::is_floating_point<Type>::value
-			|| std::is_integral<Type>::value
-			|| std::is_same<sqlite_int64, Type>::value
-		> { };
-#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
-		template <typename ...Args>
-		struct is_sqlite_value< std::variant<Args...> > : public std::integral_constant<
-			bool,
-			true
-		> { };
-#endif
-
-
 		/* for vector<T, A> support */
 		template<typename T, typename A> friend database_binder& operator <<(database_binder& db, const std::vector<T, A>& val);
 		template<typename T, typename A> friend void get_col_from_db(database_binder& db, int inx, std::vector<T, A>& val);
@@ -263,43 +220,56 @@ namespace sqlite {
 			}
 		}
 
-		template <typename Result>
-		typename std::enable_if<is_sqlite_value<Result>::value, void>::type operator>>(
-			Result& value) {
-			this->_extract_single_value([&value, this] {
-				get_col_from_db(*this, 0, value);
-			});
-		}
-
-		template<typename... Types>
-		void operator>>(std::tuple<Types...>&& values) {
-			this->_extract_single_value([&values, this] {
-				tuple_iterate<std::tuple<Types...>>::iterate(values, *this);
-			});
-		}
-
-		template <typename Function>
-		typename std::enable_if<!is_sqlite_value<Function>::value, void>::type operator>>(
-			Function&& func) {
-			typedef utility::function_traits<Function> traits;
-
-			this->_extract([&func, this]() {
-				binder<traits::arity>::run(*this, func);
-			});
-		}
 		friend class row_iterator;
 	};
+	namespace detail {
+		template <typename Type>
+		struct is_sqlite_value : public std::integral_constant<
+			bool,
+			std::is_floating_point<Type>::value
+			|| std::is_integral<Type>::value
+			|| std::is_same<std::string, Type>::value
+			|| std::is_same<std::u16string, Type>::value
+			|| std::is_same<sqlite_int64, Type>::value
+		> { };
+		template <typename Type, typename Allocator>
+		struct is_sqlite_value< std::vector<Type, Allocator> > : public std::integral_constant<
+			bool,
+			std::is_floating_point<Type>::value
+			|| std::is_integral<Type>::value
+			|| std::is_same<sqlite_int64, Type>::value
+		> { };
+		template <typename T>
+		struct is_sqlite_value< std::unique_ptr<T> > : public is_sqlite_value<T> {};
+#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
+		template <typename ...Args>
+		struct is_sqlite_value< std::variant<Args...> > : public std::integral_constant<
+			bool,
+			true
+		> { };
+#endif
+#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
+		template <typename T>
+		struct is_sqlite_value< std::optional<T> > : public is_sqlite_value<T> {};
+#endif
+
+#ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT
+		template <typename T>
+		struct is_sqlite_value< boost::optional<T> > : public is_sqlite_value<T> {};
+#endif
+	}
+
 	class row_iterator {
 	public:
 		class value_type {
 		public:
 			value_type(database_binder *_binder): _binder(_binder) {};
 			template<class T>
-			typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
+			typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
 				get_col_from_db(*_binder, next_index++, result);
 				return *this;
 			}
-			template<class T, typename = typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type>
+			template<class T, typename = typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type>
 			operator T() {
 				T result;
 				*this >> result;
@@ -313,6 +283,10 @@ namespace sqlite {
 				return *this;
 			}
 			template<class ...Types>
+			value_type &operator >>(std::tuple<Types...>&& values) {
+				return *this >> values;
+			}
+			template<class ...Types>
 			operator std::tuple<Types...>() {
 				std::tuple<Types...> value;
 				*this >> value;
@@ -332,7 +306,9 @@ namespace sqlite {
 
 		row_iterator() = default;
 		explicit row_iterator(database_binder &binder): _binder(&binder) {
-			_binder->_start_execute();
+			_binder->_next_index();
+			_binder->_inx = 0;
+			_binder->used(true);
 			++*this;
 		}
 
@@ -342,7 +318,6 @@ namespace sqlite {
 			switch(int result = sqlite3_step(_binder->_stmt.get())) {
 				case SQLITE_ROW:
 					value = {_binder};
-					/* tuple_iterate<value_type>::iterate(_value, *_binder); */
 					break;
 				case SQLITE_DONE:
 					_binder = nullptr;
@@ -374,20 +349,53 @@ namespace sqlite {
 	inline row_iterator database_binder::end() {
 		return row_iterator();
 	}
-	void database_binder::_extract(std::function<void(void)> call_back) {
-		for(auto &&row[[maybe_unused]] : *this)
-			call_back();
+
+	namespace detail {
+		template<class Callback>
+		void _extract_single_value(database_binder &binder, Callback call_back) {
+			auto iter = binder.begin();
+			if(iter == binder.end())
+				throw errors::no_rows("no rows to extract: exactly 1 row expected", binder.sql(), SQLITE_DONE);
+
+			call_back(*iter);
+
+			if(++iter != binder.end())
+				throw errors::more_rows("not all rows extracted", binder.sql(), SQLITE_ROW);
+		}
+	}
+	void database_binder::execute() {
+		for(auto &&row : *this)
+			(void)row;
+	}
+	namespace detail {
+		template<class T> using void_t = void;
+		template<class T, class = void>
+		struct sqlite_direct_result : std::false_type {};
+		template<class T>
+		struct sqlite_direct_result<
+			T,
+			void_t<decltype(std::declval<row_iterator::value_type&>().operator>>(std::declval<T&&>()))>
+		> : std::true_type {};
+	}
+	template <typename Result>
+	inline typename std::enable_if<detail::sqlite_direct_result<Result>::value>::type operator>>(database_binder &binder, Result&& value) {
+		detail::_extract_single_value(binder, [&value] (row_iterator::value_type &row) {
+			row >> std::forward<Result>(value);
+		});
 	}
 
-	void database_binder::_extract_single_value(std::function<void(void)> call_back) {
-		auto iter = begin();
-		if(iter == end())
-			throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
+	template <typename Function>
+	inline typename std::enable_if<!detail::sqlite_direct_result<Function>::value>::type operator>>(database_binder &db_binder, Function&& func) {
+		using traits = utility::function_traits<Function>;
 
-		call_back();
+		for(auto &&row : db_binder) {
+			binder<traits::arity>::run(row, func);
+		}
+	}
 
-		if(++iter != end())
-			throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW);
+	template <typename Result>
+	inline decltype(auto) operator>>(database_binder &&binder, Result&& value) {
+		return binder >> std::forward<Result>(value);
 	}
 
 	namespace sql_function_binder {
@@ -592,14 +600,13 @@ namespace sqlite {
 			std::size_t Boundary = Count
 		>
 			static typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
-				database_binder& db,
-				Function&&       function,
-				Values&&...      values
+				row_iterator::value_type& row,
+				Function&&                function,
+				Values&&...               values
 				) {
-			typename std::remove_cv<typename std::remove_reference<nth_argument_type<Function, sizeof...(Values)>>::type>::type value{};
-			get_col_from_db(db, sizeof...(Values), value);
-
-			run<Function>(db, function, std::forward<Values>(values)..., std::move(value));
+			typename std::decay<nth_argument_type<Function, sizeof...(Values)>>::type value;
+			row >> value;
+			run<Function>(row, function, std::forward<Values>(values)..., std::move(value));
 		}
 
 		template<
@@ -608,9 +615,9 @@ namespace sqlite {
 			std::size_t Boundary = Count
 		>
 			static typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run(
-				database_binder&,
-				Function&&       function,
-				Values&&...      values
+				row_iterator::value_type&,
+				Function&&                function,
+				Values&&...               values
 				) {
 			function(std::move(values)...);
 		}
diff --git a/hdr/sqlite_modern_cpp/utility/function_traits.h b/hdr/sqlite_modern_cpp/utility/function_traits.h
index cd8fab09..f629aa09 100644
--- a/hdr/sqlite_modern_cpp/utility/function_traits.h
+++ b/hdr/sqlite_modern_cpp/utility/function_traits.h
@@ -42,10 +42,11 @@ namespace sqlite {
 		> {
 			typedef ReturnType result_type;
 
+			using argument_tuple = std::tuple<Arguments...>;
 			template <std::size_t Index>
 			using argument = typename std::tuple_element<
 				Index,
-				std::tuple<Arguments...>
+				argument_tuple
 			>::type;
 
 			static const std::size_t arity = sizeof...(Arguments);

From 30f945535a5a1ad291dc50ba9a7e232c2e2baa62 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Mon, 24 Jul 2017 19:49:55 +0200
Subject: [PATCH 05/11] Less implicit conversations

---
 hdr/sqlite_modern_cpp.h | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index ee116555..c4c19c6f 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -269,12 +269,6 @@ namespace sqlite {
 				get_col_from_db(*_binder, next_index++, result);
 				return *this;
 			}
-			template<class T, typename = typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type>
-			operator T() {
-				T result;
-				*this >> result;
-				return result;
-			}
 			template<class ...Types>
 			value_type &operator >>(std::tuple<Types...>& values) {
 				assert(!next_index);

From 4b765b1634e4f88673c103b76fb3b10ed203e7c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Mon, 24 Jul 2017 20:13:46 +0200
Subject: [PATCH 06/11] Remove trailing whitespace

---
 tests/readme_example.cc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tests/readme_example.cc b/tests/readme_example.cc
index 851587a9..00523341 100644
--- a/tests/readme_example.cc
+++ b/tests/readme_example.cc
@@ -45,7 +45,7 @@ int main() {
 		db << "select age,name,weight from user where age > ? ;"
 			<< 21
 			>> [&](int _age, string _name, double _weight) {
-				if(_age != age || _name != name) 
+				if(_age != age || _name != name)
 					exit(EXIT_FAILURE);
 				cout << _age << ' ' << _name << ' ' << _weight << endl;
 		};
@@ -54,13 +54,13 @@ int main() {
 			string _name;
 			double _weight;
 			row >> _age >> _name >> _weight;
-			if(_age != age || _name != name) 
+			if(_age != age || _name != name)
 				exit(EXIT_FAILURE);
 			cout << _age << ' ' << _name << ' ' << _weight << endl;
 		}
 
 		for(std::tuple<int, string, double> row : db << "select age,name,weight from user where age > ? ;" << 21) {
-			if(std::get<int>(row) != age || std::get<string>(row) != name) 
+			if(std::get<int>(row) != age || std::get<string>(row) != name)
 				exit(EXIT_FAILURE);
 			cout << std::get<int>(row) << ' ' << std::get<string>(row) << ' ' << std::get<double>(row) << endl;
 		}

From e7614523ff7144337739465b6cbaa76389952ec4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Mon, 24 Jul 2017 22:24:21 +0200
Subject: [PATCH 07/11] Implement tuple extraction via operator>>

---
 hdr/sqlite_modern_cpp.h | 39 ++++++++++++++++++++++-----------------
 1 file changed, 22 insertions(+), 17 deletions(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index c4c19c6f..6ed747e5 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -70,17 +70,6 @@ namespace sqlite {
 
 	typedef std::shared_ptr<sqlite3> connection_type;
 
-	template<typename Tuple, int Element = 0, bool Last = (std::tuple_size<Tuple>::value == Element)> struct tuple_iterate {
-		static void iterate(Tuple& t, database_binder& db) {
-			get_col_from_db(db, Element, std::get<Element>(t));
-			tuple_iterate<Tuple, Element + 1>::iterate(t, db);
-		}
-	};
-
-	template<typename Tuple, int Element> struct tuple_iterate<Tuple, Element, true> {
-		static void iterate(Tuple&, database_binder&) {}
-	};
-
 	class row_iterator;
 	class database_binder {
 
@@ -270,12 +259,7 @@ namespace sqlite {
 				return *this;
 			}
 			template<class ...Types>
-			value_type &operator >>(std::tuple<Types...>& values) {
-				assert(!next_index);
-				tuple_iterate<std::tuple<Types...>>::iterate(values, *_binder);
-				next_index = sizeof...(Types) + 1;
-				return *this;
-			}
+			value_type &operator >>(std::tuple<Types...>& values);
 			template<class ...Types>
 			value_type &operator >>(std::tuple<Types...>&& values) {
 				return *this >> values;
@@ -336,6 +320,27 @@ namespace sqlite {
 		mutable value_type value{_binder}; // mutable, because `changing` the value is just reading it
 	};
 
+	namespace detail {
+		template<typename Tuple, int Element = 0, bool Last = (std::tuple_size<Tuple>::value == Element)> struct tuple_iterate {
+			static void iterate(Tuple& t, row_iterator::value_type& row) {
+				row >> std::get<Element>(t);
+				tuple_iterate<Tuple, Element + 1>::iterate(t, row);
+			}
+		};
+
+		template<typename Tuple, int Element> struct tuple_iterate<Tuple, Element, true> {
+			static void iterate(Tuple&, row_iterator::value_type&) {}
+		};
+	}
+
+	template<class ...Types>
+	row_iterator::value_type &row_iterator::value_type::operator >>(std::tuple<Types...>& values) {
+		assert(!next_index);
+		detail::tuple_iterate<std::tuple<Types...>>::iterate(values, *this);
+		next_index = sizeof...(Types) + 1;
+		return *this;
+	}
+
 	inline row_iterator database_binder::begin() {
 		return row_iterator(*this);
 	}

From fde544f1449600dbc8a78f84190d8fd7dec73d5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Sun, 21 Jan 2018 21:01:06 +0100
Subject: [PATCH 08/11] Added example to README

---
 README.md | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index f56869c4..c99fd27d 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,7 @@ int main() {
 
       cout << "The new record got assigned id " << db.last_insert_rowid() << endl;
 
-      // slects from user table on a condition ( age > 18 ) and executes
+      // selects from user table on a condition ( age > 18 ) and executes
       // the lambda for each row returned .
       db << "select age,name,weight from user where age > ? ;"
          << 18
@@ -56,6 +56,18 @@ int main() {
             cout << age << ' ' << name << ' ' << weight << endl;
          };
 
+      // a for loop can be used too:
+      // with named variables
+      for(auto &&row : db << "select age,name,weight from user where age > ? ;" << 18) {
+         int age; string name; double weight;
+         row >> age >> name >> weight;
+         cout << age << ' ' << name << ' ' << weight << endl;
+      }
+      // or with a tuple
+      for(tuple<int, string, double> row : db << "select age,name,weight from user where age > ? ;" << 18) {
+         cout << get<0>(row) << ' ' << get<1>(row) << ' ' << get<2>(row) << endl;
+      }
+
       // selects the count(*) from user table
       // note that you can extract a single culumn single row result only to : int,long,long,float,double,string,u16string
       int count = 0;

From 8bc7d2576360e01c11ed03010a1e7c2f29a9da9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Sun, 21 Jan 2018 22:09:19 +0100
Subject: [PATCH 09/11] Fix bug with experimental optional

---
 hdr/sqlite_modern_cpp.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index 6ed747e5..1f67f132 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -239,7 +239,7 @@ namespace sqlite {
 #endif
 #ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
 		template <typename T>
-		struct is_sqlite_value< std::optional<T> > : public is_sqlite_value<T> {};
+		struct is_sqlite_value< optional<T> > : public is_sqlite_value<T> {};
 #endif
 
 #ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT

From 73b062d2129c7e640e62e4fce60c81cc5196105d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Wed, 24 Jan 2018 09:27:54 +0100
Subject: [PATCH 10/11] Drop declaration of missing operator

---
 hdr/sqlite_modern_cpp.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index 1f67f132..fba6af1b 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -306,8 +306,6 @@ namespace sqlite {
 			return *this;
 		}
 
-		// Not well-defined
-		row_iterator operator++(int);
 		friend inline bool operator ==(const row_iterator &a, const row_iterator &b) {
 			return a._binder == b._binder;
 		}

From 65544ca206cd24cdd92ca376fb77ec4d06b01e83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= <zauguin@gmail.com>
Date: Mon, 5 Feb 2018 19:09:55 +0100
Subject: [PATCH 11/11] Make execute inline

---
 hdr/sqlite_modern_cpp.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h
index fba6af1b..a3ff93d9 100644
--- a/hdr/sqlite_modern_cpp.h
+++ b/hdr/sqlite_modern_cpp.h
@@ -360,7 +360,7 @@ namespace sqlite {
 				throw errors::more_rows("not all rows extracted", binder.sql(), SQLITE_ROW);
 		}
 	}
-	void database_binder::execute() {
+	inline void database_binder::execute() {
 		for(auto &&row : *this)
 			(void)row;
 	}