In c++ 17 the range based for has been implemented like this
{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
You may check here
If you want to make you class suitable for using the range based for loop, you should define 5 functions:
- begin()
- end()
- operator *()
- void operator ++()
- bool operator != (...& other)
And because you want that your class has an iterator and NOT is an iterator, we will simply define an internal iterator to the underlying data structure and do all operations with this iterator.
That's a difference to the other answers, where the whole class is an iterator.
This makes life real easy.
Reading the complete file is a one-liner.
By the way, parsing the file is also a one liner by using std::regex_token_iterator
. There is no need for boost or something. Reading a file and splitting it into Tokens is als a typical one-liner.
Please see the simple program below:
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
#include <regex>
#include <iterator>
#include <algorithm>
using Lines = std::vector<std::string>;
std::regex re{ "," };
class Csv {
// Here we staore all lines of the file
Lines lines{};
// Local iterator to this lines
Lines::iterator lineIterator{};
// Function to read all lines of the file
void readData(const std::string& fileName);
public:
// Simple constructor
explicit Csv(std::string fileName) { readData(fileName); }
~Csv() {};
// Iterators to access the lines data
Lines::iterator begin() { lineIterator = lines.begin(); return lineIterator; };
Lines::iterator end() { lineIterator = lines.end(); return lineIterator; };
std::string& operator *() { return *lineIterator; }
void operator ++() { ++lineIterator; }
bool operator != (const Lines::iterator& other) { return other != lineIterator; }
};
void Csv::readData(const std::string& fileName) {
// Open File and check, if it could be opened
if (std::ifstream fileStream{ fileName }; fileStream) {
// Clear old existing data
lines.clear();
// Read all lines
for (std::string line{}; std::getline(fileStream, line); lines.push_back(line))
;
}
else {
std::cerr << "\n*** Error: Could not open file '" << fileName << "'\n";
}
}
int main() {
// Open file and read all lines
Csv csv("r:\\text.txt");
// Range based for for iterating over the lines in the file
for (const std::string& line : csv) {
std::cout << "\n\n" << line << " ->\n";
std::copy(std::sregex_token_iterator(line.begin(), line.end(), re, -1), {}, std::ostream_iterator<std::string>(std::cout, "\t"));
}
return 0;
}