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

//FRAMEWORK - HELPER ETC


template<int ...>
struct seq {};

template<int M, int ...N>
struct genseq  : genseq<M-1,M-1, N...> {};

template<int ...N>
struct genseq<0,N...>
{
   typedef seq<N...> type;
};

template<typename...args>
struct tuple_maker
{
   template<int ...N>
   std::tuple<args...> make(std::istream & stream, const seq<N...> &)
   {
     return std::make_tuple(args(read_arg<N>(stream))...);
   }
   std::vector<std::string> m_params;
   std::vector<std::unique_ptr<std::stringstream>> m_streams;
   template<int Index>
   std::stringstream & read_arg(std::istream & stream) 
   {
     if ( m_params.empty() )
     {
        std::string line;
        while ( std::getline(stream, line) ) //read all at once!
        {
                m_params.push_back(line);
        }
     }
     auto pstream = new std::stringstream(m_params.at(Index));
     m_streams.push_back(std::unique_ptr<std::stringstream>(pstream));
     return *pstream;
   }
};

//PARSE FUNCTION 
template<typename... args>
std::tuple<args...> parse(std::istream &stream) 
{
  const int N = sizeof...(args);
  return tuple_maker<args...>().make(stream, typename genseq<N>::type() );
}

///TEST CODE

template<int N>
struct A 
{
    std::string data;
	A(std::istream & stream) 
	{
		stream >> data;
	}
	friend std::ostream& operator << (std::ostream & out, A<N> const & a)
	{
		return out << "A" << N << "::data = " << a.data ;
	}
};
typedef A<1> A1;
typedef A<2> A2;
typedef A<3> A3;

int main()
{
	std::stringstream ss("A1\nA2\nA3\n");
	auto tuple = parse<A1,A2,A3>(ss);
	std::cout << std::get<0>(tuple) << std::endl;
	std::cout << std::get<1>(tuple) << std::endl;
	std::cout << std::get<2>(tuple) << std::endl;
}
