53 static constexpr struct
55 int major {CSVPP_VERSION_MAJOR},
56 minor {CSVPP_VERSION_MINOR},
57 patch {CSVPP_VERSION_PATCH};
63 class Error:
virtual public std::exception
66 virtual ~Error() =
default;
68 const char *
what()
const throw()
override {
return msg_.c_str(); }
71 explicit Error(
const std::string & msg): msg_{msg} {}
95 Error{
"Error parsing CSV at line: " +
103 std::string
type()
const {
return type_; }
132 Error{
"Could not convert '" +
field +
"' to requested type"},
137 std::string
field()
const {
return field_; }
157 std::string
errno_str()
const {
return std::strerror(errno_code_); }
167 template <
typename T,
typename =
void>
168 struct has_std_to_string: std::false_type{};
169 template <
typename T>
170 struct has_std_to_string<T, std::void_t<decltype(std::to_string(std::declval<T>()))>> : std::true_type{};
171 template <
typename T>
172 inline constexpr bool has_std_to_string_v = has_std_to_string<T>::value;
175 template <
typename T,
typename =
void>
176 struct has_to_string: std::false_type{};
177 template <
typename T>
178 struct has_to_string<T, std::void_t<decltype(to_string(std::declval<T>()))>> : std::true_type{};
179 template <
typename T>
180 inline constexpr bool has_to_string_v = has_to_string<T>::value;
183 template <
typename T,
typename =
void>
184 struct has_ostr: std::false_type{};
185 template <
typename T>
186 struct has_ostr<T, std::void_t<decltype(std::declval<std::ostringstream&>() << std::declval<T>())>> : std::true_type{};
187 template <typename T>
188 inline constexpr bool has_ostr_v = has_ostr<T>::value;
196 template <typename T, typename std::enable_if_t<std::is_convertible_v<T, std::string>, int> = 0>
197 std::string str(const T & t)
202 template <typename T, typename std::enable_if_t<!std::is_convertible_v<T, std::string> && detail::has_std_to_string_v<T>, int> = 0>
203 std::string str(const T & t)
205 return std::to_string(t);
208 template <typename T, typename std::enable_if_t<!std::is_convertible_v<T, std::string> && !detail::has_std_to_string_v<T> && detail::has_to_string_v<T>, int> = 0>
209 std::string str(const T & t)
214 template <typename T, typename std::enable_if_t<!std::is_convertible_v<T, std::string> && !detail::has_std_to_string_v<T> && !detail::has_to_string_v<T> && detail::has_ostr_v<T>, int> = 0>
215 std::string str(const T & t)
217 std::ostringstream os;
223 std::string str(char c)
255 template <typename T = std::string> class Iterator
258 using value_type = T;
259 using difference_type = std::ptrdiff_t;
260 using pointer = const T*;
261 using reference = const T&;
262 using iterator_category = std::input_iterator_tag;
267 Iterator(): row_{nullptr} {}
276 explicit Iterator(Reader::Row & row): row_{&row}
282 const T & operator*() const { return obj_; }
285 const T * operator->() const { return &obj_; }
292 Iterator & operator++()
302 obj_ = row_->read_field<T>();
304 if(row_->end_of_row())
312 bool equals(const Iterator<T> & rhs) const
314 return row_ == rhs.row_;
320 bool end_of_row_ =
false;
326 template<
typename T = std::
string>
343 explicit Range(
Row & row):row_{row} {}
349 template<
typename T = std::
string>
357 template<
typename T = std::
string>
368 template<
typename T = std::
string>
381 template<
typename T = std::
string>
388 past_end_of_row_ =
true;
392 auto field = reader_->read_field<T>();
394 if(reader_->end_of_row())
411 data = read_field<T>();
422 template<
typename T = std::
string,
typename OutputIter>
425 std::copy(begin<T>(), end<T>(), it);
435 template<
typename T = std::
string>
439 std::copy(begin<T>(), end<T>(), std::back_inserter(vec));
452 template <
typename ... Args>
455 std::tuple<Args...> ret;
456 read_tuple_helper(ret, std::index_sequence_for<Args...>{});
468 template <
typename ... Data>
471 (void)(*
this >> ... >> data);
478 operator bool() {
return reader_ && !past_end_of_row_; }
487 template <
typename Tuple, std::size_t ... Is>
488 void read_tuple_helper(Tuple & t, std::index_sequence<Is...>)
490 ((*
this >> std::get<Is>(t)), ...);
496 Row(): reader_{nullptr} {}
501 explicit Row(Reader & reader): reader_{&reader} {}
503 Reader * reader_ {
nullptr };
504 bool end_of_row_ {
false };
505 bool past_end_of_row_ {
false };
513 using difference_type = std::ptrdiff_t;
516 using iterator_category = std::input_iterator_tag;
551 while(!obj_.end_of_row())
555 obj_ = reader_->get_row();
566 return reader_ == rhs.reader_;
570 Reader * reader_ {
nullptr };
581 explicit Reader(std::istream & input_stream,
582 const char delimiter =
',',
const char quote =
'"',
583 const bool lenient =
false):
584 input_stream_{&input_stream},
585 delimiter_{delimiter},
597 explicit Reader(
const std::string & filename,
598 const char delimiter =
',',
const char quote =
'"',
599 const bool lenient =
false):
600 internal_input_stream_{std::make_unique<std::ifstream>(filename)},
601 input_stream_{internal_input_stream_.get()},
602 delimiter_{delimiter},
606 if(!(*internal_input_stream_))
607 throw IO_error(
"Could not open file '" + filename +
"'", errno);
631 const char delimiter =
',',
const char quote =
'"',
632 const bool lenient =
false):
633 internal_input_stream_{std::make_unique<std::istringstream>(input_data)},
634 input_stream_{internal_input_stream_.get()},
635 delimiter_{delimiter},
655 bool eof()
const {
return state_ == State::eof; }
658 operator bool() {
return !eof(); }
695 template<
typename T = std::
string>
704 if(conversion_retry_)
706 field = *conversion_retry_;
707 conversion_retry_.reset();
715 if constexpr(std::is_convertible_v<std::string, T>)
722 std::istringstream convert(field);
724 if(!convert || convert.peek() != std::istream::traits_type::eof())
726 conversion_retry_ = field;
745 data = read_field<T>();
760 template <
typename ... Data>
763 (void)(*
this >> ... >> data);
786 template <
typename T = std::
string,
typename OutputIter>
789 auto row = get_row();
804 template <
typename T = std::
string>
807 auto row = get_row();
811 return row.read_vec<T>();
824 template <
typename ... Args>
827 auto row = get_row();
831 return row.read_tuple<Args...>();
841 template <
typename T = std::
string>
844 std::vector<std::vector<T>> data;
847 auto row = read_row_vec<T>();
849 data.push_back(*row);
865 int c = input_stream_->get();
866 if(input_stream_->bad() && !input_stream_->eof())
867 throw IO_error{
"Error reading from input", errno};
874 else if(c != std::istream::traits_type::eof())
884 void consume_newlines()
886 if(state_ != State::consume_newlines)
891 if(
int c = getc(); c == std::istream::traits_type::eof())
897 else if(c !=
'\r' && c !=
'\n')
899 state_ = State::read;
900 input_stream_->unget();
923 bool field_done =
false;
934 if(c == delimiter_ || c ==
'\n' || c ==
'\r' || c == std::istream::traits_type::eof())
937 state_ = State::read;
944 state_ = State::read;
952 state_ = State::read;
957 throw Parse_error(
"Unescaped quote", line_no_, col_no_ - 1);
965 state_ = State::quote;
980 throw Parse_error(
"quote found in unquoted field", line_no_, col_no_);
985 if(quoted && c == std::istream::traits_type::eof())
989 end_of_row_ = field_done = c_done =
true;
990 state_ = State::consume_newlines;
994 throw Parse_error(
"Unterminated quoted field - reached end-of-file", line_no_, col_no_);
996 else if(!quoted && c == delimiter_)
998 field_done = c_done =
true;
1001 else if(!quoted && (c ==
'\n' || c ==
'\r' || c == std::istream::traits_type::eof()))
1003 end_of_row_ = field_done = c_done =
true;
1004 state_ = State::consume_newlines;
1014 throw Internal_error{
"Illegal state"};
1024 std::unique_ptr<std::istream> internal_input_stream_;
1029 std::istream * input_stream_;
1031 char delimiter_ {
','};
1033 bool lenient_ {
false };
1035 std::optional<std::string> conversion_retry_;
1036 bool end_of_row_ {
false };
1048 State state_ { State::consume_newlines };
1050 unsigned int line_no_ { 1 };
1051 unsigned int col_no_ { 0 };
1067 template <
typename T>
1074 template <
typename T>
1086 template <
typename Header = std::
string,
typename Value = std::
string>
1090 std::unique_ptr<Reader> reader_;
1092 std::vector<Header> headers_;
1093 std::map<Header, Value> obj_;
1103 std::vector<Header> get_header_row(
const std::vector<Header> & headers)
1105 if(!std::empty(headers))
1108 auto header_row = reader_->read_row_vec<Header>();
1115 template <
typename Header2,
typename Value2>
1140 explicit Map_reader_iter(std::istream & input_stream,
const Value & default_val = {},
const std::vector<Header> & headers = {},
1141 const char delimiter =
',',
const char quote =
'"',
1142 const bool lenient =
false):
1143 reader_{std::make_unique<Reader>(input_stream, delimiter, quote, lenient)},
1144 default_val_{default_val},
1145 headers_{get_header_row(headers)}
1164 explicit Map_reader_iter(
const std::string & filename,
const Value & default_val = {},
const std::vector<Header> & headers = {},
1165 const char delimiter =
',',
const char quote =
'"',
1166 const bool lenient =
false):
1167 reader_{std::make_unique<Reader>(filename, delimiter, quote, lenient)},
1168 default_val_{default_val},
1169 headers_{get_header_row(headers)}
1191 const char delimiter =
',',
const char quote =
'"',
1192 const bool lenient =
false):
1193 reader_{std::make_unique<Reader>(Reader::input_string, input_data, delimiter, quote, lenient)},
1194 default_val_{default_val},
1195 headers_{get_header_row(headers)}
1200 using value_type = std::map<Header, Value>;
1201 using difference_type = std::ptrdiff_t;
1202 using pointer =
const value_type*;
1203 using reference =
const value_type&;
1204 using iterator_category = std::input_iterator_tag;
1208 value_type & operator*() {
return obj_; }
1212 value_type * operator->() {
return &obj_; }
1220 const typename value_type::mapped_type &
operator[](
const typename value_type::key_type & key)
const {
return obj_.at(key); }
1221 typename value_type::mapped_type & operator[](
const typename value_type::key_type & key) {
return obj_.at(key); }
1230 auto row = reader_->read_row_vec<Value>();
1235 if(std::size(*row) > std::size(headers_))
1238 for(std::size_t i = 0; i < std::size(*row); ++i)
1239 obj_[headers_[i]] = (*row)[i];
1241 for(std::size_t i = std::size(*row); i < std::size(headers_); ++i)
1242 obj_[headers_[i]] = default_val_;
1249 template <
typename Header2,
typename Value2>
1252 return reader_ == rhs.reader_;
1265 template <
typename Header1,
typename Value1,
typename Header2,
typename Value2>
1272 template <
typename Header1,
typename Value1,
typename Header2,
typename Value2>
1293 using value_type = void;
1294 using difference_type = void;
1295 using pointer = void;
1296 using reference = void;
1297 using iterator_category = std::output_iterator_tag;
1316 template <
typename T>
1319 writer_.write_field(field);
1333 explicit Writer(std::ostream & output_stream,
1334 const char delimiter =
',',
const char quote =
'"'):
1335 output_stream_{&output_stream},
1336 delimiter_{delimiter},
1348 const char delimiter =
',',
const char quote =
'"'):
1349 internal_output_stream_{std::make_unique<std::ofstream>(filename, std::ios::binary)},
1350 output_stream_{internal_output_stream_.get()},
1351 delimiter_{delimiter},
1354 if(!(*internal_output_stream_))
1355 throw IO_error(
"Could not open file '" + filename +
"'", errno);
1400 template<
typename T>
1405 (*output_stream_)<<delimiter_;
1406 if(output_stream_->bad())
1407 throw IO_error{
"Error writing to output", errno};
1410 (*output_stream_)<<quote(field);
1411 if(output_stream_->bad())
1412 throw IO_error{
"Error writing to output", errno};
1414 start_of_row_ =
false;
1422 template<
typename T>
1444 (*output_stream_)<<
"\r\n";
1445 if(output_stream_->bad())
1446 throw IO_error{
"Error writing to output", errno};
1447 start_of_row_ =
true;
1456 template<
typename Iter>
1459 for(; first != last; ++first)
1460 write_field(*first);
1468 template<
typename T>
1471 write_fields(std::begin(data), std::end(data));
1482 template<
typename Range>
1485 write_fields(std::begin(data), std::end(data));
1493 template<
typename ...Data>
1496 (void)(*
this << ... << data);
1505 template<
typename ...Args>
1508 std::apply(&Writer::write_fields_v<Args...>, std::tuple_cat(std::tuple(std::ref(*
this)), data));
1517 template<
typename Iter>
1520 write_fields(first, last);
1530 template<
typename T>
1533 write_row(std::begin(data), std::end(data));
1544 template<
typename Range>
1547 write_row(std::begin(data), std::end(data));
1555 template<
typename ...Data>
1558 (void)(*
this << ... << data);
1569 template<
typename ...Args>
1572 std::apply(&Writer::write_row_v<Args...>, std::tuple_cat(std::tuple(std::ref(*
this)), data));
1581 template<
typename T>
1582 std::string quote(
const T & field)
1584 std::string field_str =
str(field);
1586 std::string ret{quote_};
1587 ret.reserve(std::size(field_str) + 2);
1588 bool quoted =
false;
1589 for(
auto c: field_str)
1596 else if(c == delimiter_ || c ==
'\r' || c ==
'\n')
1609 friend Writer &
end_row(Writer & w);
1612 std::unique_ptr<std::ostream> internal_output_stream_;
1617 std::ostream * output_stream_;
1618 bool start_of_row_ {
true};
1620 char delimiter_ {
','};
1637 template <
typename Header,
typename Default_value = std::
string>
1641 std::unique_ptr<Writer> writer_;
1642 std::vector<Header> headers_;
1643 Default_value default_val_;
1654 Map_writer_iter(std::ostream & output_stream,
const std::vector<Header> & headers,
const Default_value & default_val = {},
1655 const char delimiter =
',',
const char quote =
'"'):
1656 writer_{std::make_unique<
Writer>(output_stream, delimiter, quote)}, headers_{headers}, default_val_{default_val}
1670 Map_writer_iter(
const std::string& filename,
const std::vector<Header> & headers,
const Default_value & default_val = {},
1671 const char delimiter =
',',
const char quote =
'"'):
1672 writer_{std::make_unique<
Writer>(filename, delimiter, quote)}, headers_{headers}, default_val_{default_val}
1677 using value_type = void;
1678 using difference_type = void;
1679 using pointer = void;
1680 using reference = void;
1681 using iterator_category = std::output_iterator_tag;
1697 template <
typename K,
typename T,
typename std::enable_if_t<std::is_convertible_v<Header, K>,
int> = 0>
1700 for(
auto & h: headers_)
1704 (*writer_)<<row.at(h);
1706 catch(std::out_of_range&)
1708 (*writer_)<<default_val_;
Error base class.
Definition csv.hpp:64
const char * what() const override
Definition csv.hpp:68
IO error.
Definition csv.hpp:146
IO_error(const std::string &msg, int errno_code)
Definition csv.hpp:150
std::string errno_str() const
Definition csv.hpp:157
int errno_code() const
Definition csv.hpp:155
Map-based Reader iterator.
Definition csv.hpp:1088
const value_type & operator*() const
Definition csv.hpp:1207
Map_reader_iter(std::istream &input_stream, const Value &default_val={}, const std::vector< Header > &headers={}, const char delimiter=',', const char quote='"', const bool lenient = false)
Open a std::istream for CSV parsing.
Definition csv.hpp:1140
Map_reader_iter & operator++()
Iterate to next field.
Definition csv.hpp:1228
Map_reader_iter()
Empty constructor.
Definition csv.hpp:1122
bool equals(const Map_reader_iter< Header2, Value2 > &rhs) const
Compare to another Map_reader_iter.
Definition csv.hpp:1250
std::vector< Header > get_headers() const
Get the headers.
Definition csv.hpp:1258
const value_type * operator->() const
Definition csv.hpp:1211
Map_reader_iter(const std::string &filename, const Value &default_val={}, const std::vector< Header > &headers={}, const char delimiter=',', const char quote='"', const bool lenient = false)
Open a file for CSV parsing.
Definition csv.hpp:1164
const value_type::mapped_type & operator[](const typename value_type::key_type &key) const
Get a field from the current row.
Definition csv.hpp:1220
Map_reader_iter(Reader::input_string_t, const std::string &input_data, const Value &default_val={}, const std::vector< Header > &headers={}, const char delimiter=',', const char quote='"', const bool lenient = false)
Parse CSV from memory.
Definition csv.hpp:1190
Map-based Writer iterator.
Definition csv.hpp:1639
Map_writer_iter & operator++(int)
No-op.
Definition csv.hpp:1688
Map_writer_iter(std::ostream &output_stream, const std::vector< Header > &headers, const Default_value &default_val={}, const char delimiter=',', const char quote='"')
Use a std::ostream for CSV output.
Definition csv.hpp:1654
Map_writer_iter & operator*()
No-op.
Definition csv.hpp:1684
Map_writer_iter & operator++()
No-op.
Definition csv.hpp:1686
Map_writer_iter(const std::string &filename, const std::vector< Header > &headers, const Default_value &default_val={}, const char delimiter=',', const char quote='"')
Open a file for CSV output.
Definition csv.hpp:1670
Map_writer_iter & operator=(const std::map< K, T > &row)
Write a row.
Definition csv.hpp:1698
Parsing error.
Definition csv.hpp:89
std::string type() const
Definition csv.hpp:103
int col_no() const
Definition csv.hpp:107
int line_no() const
Definition csv.hpp:105
Parse_error(const std::string &type, int line_no, int col_no)
Definition csv.hpp:94
Iterates over Rows in CSV data.
Definition csv.hpp:510
const value_type * operator->() const
Definition csv.hpp:542
const value_type & operator*() const
Definition csv.hpp:536
bool equals(const Iterator &rhs) const
Compare to another Reader::Iterator.
Definition csv.hpp:564
Iterator & operator++()
Iterate to next Row.
Definition csv.hpp:548
value_type & operator*()
Definition csv.hpp:539
value_type * operator->()
Definition csv.hpp:545
Iterator(Reader &r)
Creates an iterator from a Reader object.
Definition csv.hpp:527
Iterator()
Empty constructor.
Definition csv.hpp:521
Iterates over the fields within a Row.
Definition csv.hpp:256
bool equals(const Iterator< T > &rhs) const
Compare to another Reader::Row::Iterator.
Definition csv.hpp:312
Helper class for iterating over a Row. Use Row::range to obtain.
Definition csv.hpp:328
Row::Iterator< T > begin()
Definition csv.hpp:331
Row::Iterator< T > end()
Definition csv.hpp:337
Represents a single row of CSV data.
Definition csv.hpp:250
std::vector< T > read_vec()
Reads row into a std::vector.
Definition csv.hpp:436
std::tuple< Args... > read_tuple()
Reads row into a tuple.
Definition csv.hpp:453
void read(OutputIter it)
Reads row into an output iterator.
Definition csv.hpp:423
Row & operator>>(T &data)
Read a single field from the row.
Definition csv.hpp:409
Row::Iterator< T > end()
Definition csv.hpp:358
Range< T > range()
Range helper.
Definition csv.hpp:369
T read_field()
Read a single field from the row.
Definition csv.hpp:382
bool end_of_row() const
Definition csv.hpp:475
Row::Iterator< T > begin()
Definition csv.hpp:350
void read_v(Data &... data)
Reads row into variadic arguments.
Definition csv.hpp:469
Parses CSV data.
Definition csv.hpp:243
Iterator begin()
Definition csv.hpp:676
Row get_row()
Get the current Row.
Definition csv.hpp:769
bool eof() const
Check for end of row.
Definition csv.hpp:655
void read_v(Data &... data)
Reads fields into variadic arguments.
Definition csv.hpp:761
std::optional< std::vector< T > > read_row_vec()
Reads current row into a std::vector.
Definition csv.hpp:805
bool end_of_row() const
Check for end of input.
Definition csv.hpp:650
T read_field()
Read a single field.
Definition csv.hpp:696
bool read_row(OutputIter it)
Reads current row into an output iterator.
Definition csv.hpp:787
auto end()
Definition csv.hpp:682
Reader(const std::string &filename, const char delimiter=',', const char quote='"', const bool lenient = false)
Open a file for CSV parsing.
Definition csv.hpp:597
Reader(input_string_t, const std::string &input_data, const char delimiter=',', const char quote='"', const bool lenient = false)
Parse CSV from memory.
Definition csv.hpp:630
void set_lenient(const bool lenient)
Enable / disable lenient parsing.
Definition csv.hpp:673
std::optional< std::tuple< Args... > > read_row_tuple()
Reads current row into a tuple.
Definition csv.hpp:825
Reader & operator>>(T &data)
Read a single field.
Definition csv.hpp:743
void set_quote(const char quote)
Change the quote character.
Definition csv.hpp:667
std::vector< std::vector< T > > read_all()
Read entire CSV data into a vector of vectors.
Definition csv.hpp:842
Reader(std::istream &input_stream, const char delimiter=',', const char quote='"', const bool lenient = false)
Use a std::istream for CSV parsing.
Definition csv.hpp:581
void set_delimiter(const char delimiter)
Change the delimiter character.
Definition csv.hpp:663
Output iterator for writing CSV data field-by-field.
Definition csv.hpp:1291
Iterator & operator*()
No-op.
Definition csv.hpp:1305
Iterator & operator=(const T &field)
Writes a field to the CSV output.
Definition csv.hpp:1317
Iterator(Writer &w)
Creates an iterator from a Writer object.
Definition csv.hpp:1302
Iterator & operator++()
No-op.
Definition csv.hpp:1307
Iterator & operator++(int)
No-op.
Definition csv.hpp:1309
CSV writer.
Definition csv.hpp:1285
void write_fields(const std::tuple< Args... > &data)
Write fields from a tuple, without ending the row.
Definition csv.hpp:1506
Writer(const std::string &filename, const char delimiter=',', const char quote='"')
Open a file for CSV output.
Definition csv.hpp:1347
void write_row(Iter first, Iter last)
Definition csv.hpp:1518
~Writer()
Destructor.
Definition csv.hpp:1361
Iterator iterator()
Get iterator.
Definition csv.hpp:1380
void write_fields(Iter first, Iter last)
Definition csv.hpp:1457
Writer & operator<<(const T &field)
Writes a field to the CSV output.
Definition csv.hpp:1423
void write_row(const Range &data)
Write a row from a range.
Definition csv.hpp:1545
void end_row()
End the current row.
Definition csv.hpp:1442
void write_row(const std::tuple< Args... > &data)
Write a row from a tuple.
Definition csv.hpp:1570
void write_fields_v(const Data &...data)
Write fields from the given variadic parameters, without ending the row.
Definition csv.hpp:1494
void set_delimiter(const char delimiter)
Change the delimiter character.
Definition csv.hpp:1388
void set_quote(const char quote)
Change the quote character.
Definition csv.hpp:1393
void write_row_v(const Data &...data)
Write a row from the given variadic parameters.
Definition csv.hpp:1556
void write_fields(const std::initializer_list< T > &data)
Definition csv.hpp:1469
Writer(std::ostream &output_stream, const char delimiter=',', const char quote='"')
Use a std::ostream for CSV output.
Definition csv.hpp:1333
void write_field(const T &field)
Writes a field to the CSV output.
Definition csv.hpp:1401
Writer & operator<<(Writer &(*manip)(Writer &))
Apply a stream manipulator to the CSV output.
Definition csv.hpp:1433
void write_row(const std::initializer_list< T > &data)
Definition csv.hpp:1531
void write_fields(const Range &data)
Write fields from a range, without ending the row.
Definition csv.hpp:1483
bool operator!=(const Reader::Iterator &lhs, const Reader::Iterator &rhs)
Compare two Reader::Iterator objects.
Definition csv.hpp:1061
bool operator==(const Reader::Iterator &lhs, const Reader::Iterator &rhs)
Compare two Reader::Iterator objects.
Definition csv.hpp:1055
std::string str(const T &t)
String conversion.
Definition csv.hpp:197
Writer & end_row(Writer &w)
End row stream manipulator for Writer.
Definition csv.hpp:1628
CSV library namespace.
Definition csv.hpp:48
Internal error.
Definition csv.hpp:80
Internal_error(const std::string &msg)
Definition csv.hpp:82
Out of range error.
Definition csv.hpp:119
Out_of_range_error(const std::string &msg)
Definition csv.hpp:121
Type conversion error.
Definition csv.hpp:128
std::string field() const
Definition csv.hpp:137
Type_conversion_error(const std::string &field)
Definition csv.hpp:131