#include <vector>
#include <tuple>
#include <string>
#include <iostream>


// BORROWED FROM http://stackoverflow.com/a/15036110/592323

//===========================================================================
// META-FUNCTIONS FOR CREATING INDEX LISTS

// The structure that encapsulates index lists
template <size_t... Is>
struct index_list
{
};

// Collects internal details for generating index ranges [MIN, MAX)
namespace detail
{
    // Declare primary template for index range builder
    template <size_t MIN, size_t N, size_t... Is>
    struct range_builder;

    // Base step
    template <size_t MIN, size_t... Is>
    struct range_builder<MIN, MIN, Is...>
    {
        typedef index_list<Is...> type;
    };

    // Induction step
    template <size_t MIN, size_t N, size_t... Is>
    struct range_builder : public range_builder<MIN, N - 1, N - 1, Is...>
    {
    };
}

// Meta-function that returns a [MIN, MAX) index range
template<size_t MIN, size_t MAX>
using index_range = typename detail::range_builder<MIN, MAX>::type;

//===========================================================================



template<std::size_t I = 0, typename ...Ts>
inline typename std::enable_if<I == sizeof...(Ts), void>::type
tupleIncrement(std::tuple<Ts...> &tup)
{ }
template<std::size_t I = 0, typename ...Ts>
inline typename std::enable_if<I < sizeof...(Ts), void>::type
tupleIncrement(std::tuple<Ts...> &tup)
{
    ++std::get<I>(tup); 
    tupleIncrement<I + 1, Ts...>(tup);
}


template<typename ...Ts> // Element types
class WrapMultiVector
{
    // references to vectors in a TUPLE
    std::tuple<std::vector<Ts>&...> m_vectors;
    
    // list of indices
    typedef decltype(index_range<0, sizeof...(Ts)>()) IndexList;

public:
    // references to vectors in multiple arguments
    WrapMultiVector(std::vector<Ts> & ...vectors)
        : m_vectors(vectors...)    // construct tuple from multiple args.
    {}
    
    
    
    class iterator {
        std::tuple<typename std::vector<Ts>::iterator...> m_elemIterators;

    public:
        iterator(std::tuple<typename std::vector<Ts>::iterator...> elemIterators) 
            : m_elemIterators(elemIterators)
        {}

        bool operator==(const iterator &o) const {
            return std::get<0>(m_elemIterators) == std::get<0>(o.m_elemIterators);
        }
        bool operator!=(const iterator &o) const {
            return std::get<0>(m_elemIterators) != std::get<0>(o.m_elemIterators);
        }

        iterator& operator ++() {
            tupleIncrement(m_elemIterators);
            return *this;
        }
        iterator operator ++(int) {
            iterator old = *this;
            tupleIncrement(m_elemIterators);
            return old;
        }

        std::tuple<Ts&...> operator*() {
            return getElements(IndexList());
        }
        
    private:
    	template<size_t ...Is>
    	std::tuple<Ts&...> getElements(index_list<Is...>) {
    		return std::tie(*std::get<Is>(m_elemIterators)...);
    	}
    };
    
    
    iterator begin() {
    	return iterator(getBegins(IndexList()));
    }
    iterator end() {
    	return iterator(getEnds(IndexList()));
    }
    
private:
	template<size_t ...Is>
	std::tuple<typename std::vector<Ts>::iterator...> getBegins(index_list<Is...>) {
		return std::make_tuple(std::get<Is>(m_vectors).begin()...);
	}
	template<size_t ...Is>
	std::tuple<typename std::vector<Ts>::iterator...> getEnds(index_list<Is...>) {
		return std::make_tuple(std::get<Is>(m_vectors).end()...);
	}
};



template<typename ...Ts>
WrapMultiVector<Ts...> makeWrapper(std::vector<Ts> & ...vectors) {
    return WrapMultiVector<Ts...>(vectors...);
}


int main() {
	std::vector<int> id           = { 1,       2,     3       };
	std::vector<std::string> name = { "Alice", "Bob", "Carol" };
	std::vector<int> age          = { 30,      42,    55      };
	
	auto nameAge = makeWrapper(name, age);
	for (auto na : nameAge) {
		std::cout << "name: " << std::get<0>(na) << ", age: " << std::get<1>(na) << std::endl;
	}
}
