Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision f2ff0a6c85d80b8cad7c70285ea4d2df2de55cf6)
+++ src/Common/utility.h	(revision 6411b7dd3a9f8dd2239e53564c5cb46c1c838092)
@@ -457,12 +457,13 @@
 // TODO: update to use variadic arguments
 
+template< typename... >
+struct group_iterate_t;
+
 template< typename T1, typename T2 >
-struct group_iterate_t {
+struct group_iterate_t<T1, T2> {
 private:
 	std::tuple<T1, T2> args;
 public:
-	group_iterate_t( bool skipBoundsCheck, const T1 & v1, const T2 & v2 ) : args(v1, v2) {
-		assertf(skipBoundsCheck || v1.size() == v2.size(), "group iteration requires containers of the same size: <%zd, %zd>.", v1.size(), v2.size());
-	};
+	group_iterate_t( const T1 & v1, const T2 & v2 ) : args(v1, v2) {};
 
 	typedef std::tuple<decltype(*std::get<0>(args).begin()), decltype(*std::get<1>(args).begin())> value_type;
@@ -485,8 +486,47 @@
 };
 
+template< typename T1, typename T2, typename T3 >
+struct group_iterate_t<T1, T2, T3> {
+private:
+	std::tuple<T1, T2, T3> args;
+public:
+	group_iterate_t( const T1 & v1, const T2 & v2, const T3 & v3 ) : args(v1, v2, v3) {};
+
+	template<size_t I> using Iter = decltype(std::get<I>(args).begin());
+	using value_type = std::tuple<decltype(*std::get<0>(args).begin()), decltype(*std::get<1>(args).begin()), decltype(*std::get<2>(args).begin())>;
+
+	struct iterator {
+		typedef std::tuple<Iter<0>, Iter<1>, Iter<2>> IterTuple;
+		IterTuple it;
+		iterator( Iter<0> i0, Iter<1> i1, Iter<2> i2 ) : it( i0, i1, i2 ) {}
+		iterator operator++() {
+			return iterator( ++std::get<0>(it), ++std::get<1>(it), ++std::get<2>(it) );
+		}
+		bool operator!=( const iterator &other ) const { return it != other.it; }
+		value_type operator*() const { return std::tie( *std::get<0>(it), *std::get<1>(it), *std::get<2>(it) ); }
+	};
+
+	iterator begin() { return iterator( std::get<0>(args).begin(), std::get<1>(args).begin(), std::get<2>(args).begin() ); }
+    iterator end() { return iterator( std::get<0>(args).end(), std::get<1>(args).end(), std::get<2>(args).end() ); }
+};
+
+// Helpers for the bounds checks:
+static inline void runGroupBoundsCheck(size_t size0, size_t size1) {
+	assertf( size0 == size1,
+		"group iteration requires containers of the same size: <%zd, %zd>.",
+		size0, size1 );
+}
+
+static inline void runGroupBoundsCheck(size_t size0, size_t size1, size_t size2) {
+	assertf( size0 == size1 && size1 == size2,
+		"group iteration requires containers of the same size: <%zd, %zd, %zd>.",
+		size0, size1, size2 );
+}
+
 /// performs bounds check to ensure that all arguments are of the same length.
 template< typename... Args >
 group_iterate_t<Args...> group_iterate( Args &&... args ) {
-	return group_iterate_t<Args...>(false, std::forward<Args>( args )...);
+	runGroupBoundsCheck( args.size()... );
+	return group_iterate_t<Args...>( std::forward<Args>( args )... );
 }
 
@@ -494,5 +534,5 @@
 template< typename... Args >
 group_iterate_t<Args...> unsafe_group_iterate( Args &&... args ) {
-	return group_iterate_t<Args...>(true, std::forward<Args>( args )...);
+	return group_iterate_t<Args...>( std::forward<Args>( args )... );
 }
 
