c++templatescsvlexical-cast

Parse and cast csv based on map type c++


Does anyone know of any libraries or examples which will read/write a csv and depending on map (potentially nested) passed to infer the type and populate the map.

This will probably involve some recursive templated code.

ie map<int, map< double, map< string, double > > > would expect a csv of the format 123,93.003,BLAH,42.24

or map<Date, map< string, vector< double > > > // arbitary length vector 1/1/2013,BLAH,0.1,0.2,0.3,0.4.....0.99

Thanks.


Solution

  • Here's what I came up with

    #include <iostream>
    #include <algorithm>
    #include <iterator>
    #include <tuple>
    #include <typeinfo>
    
    using std::tuple;
    using std::get;
    
    template< class... Args >
    struct parser;
    
    // Specialization for std::tuple
    template< class... Args >
    struct parser<tuple<Args...>> {
       typedef tuple<Args...> tuple_type;
    
       static tuple_type parse( std::istream& is ) {
          tuple<Args...> result;
          _parse<0, tuple_type>::parse(is, result);
          return result;
       }
    
    private:
       template< size_t N, class T >
       struct _parse;
    
       template< size_t N, class A0, class... An >
       struct _parse<N, tuple<A0, An...>> {
          static void parse( std::istream& is, tuple_type& t ) {
    
             std::cout << "Enter " << typeid(A0).name() << ": ";
             if (!( is >> get<N>(t) ))
             { std::cout << "Bad input!\n"; is.clear(); }
             is.get();
    
             // Recurse on the rest of the list
             _parse<N+1, tuple<An...>>::parse(is, t);
          }
       };
    
       // Termination
       template< size_t N >
       struct _parse<N, tuple<>> {
          static void parse( std::istream& is, tuple_type& t ) {
             /* */
          }
       };
    };
    
    int main() {
       typedef tuple<int, double, char> tuple_type;
       tuple_type t = parser<tuple_type>::parse( std::cin );
    
       std::cout << get<0>(t) << ", " << get<1>(t) << ", " << get<2>(t) << std::endl;
    }
    

    Output

    $ ./a.out
    Enter i: 0
    Enter d: 0.0
    Enter c: w
    0, 0, w
    
    
    $ ./a.out
    Enter i: 0
    Enter d: 0.0
    Enter c: w
    0, 0, w