Let's say I want to make a file parser which uses the strategy-like pattern to allow use of different specific parsers which would do all the hard work and then returned the results which could vary between them.
For example file contains A, B, C, D and E in each line and I want to get only A, C and E, so I create a specific parser that pulls out just them.
I should also note that I'm dealing with NMEA format and each parser would handle different statements (lines) from the file.
class FileParser
{
std::string file_path;
public:
FileParser(std::string file_path, ??? parser);
void parseFile() {
// ...
// for each line:
parser.parseStatement(line);
// end for
// ...
}
??? getResults() {
return parser.getResults();
}
};
class Parser
{
public:
virtual void parseLine(std::string line);
??? getResults();
}
class SpecificParser : public Parser
{
void parseLine(std::string line);
SpecificFormat getResults();
}
And my problem is - how to correctly write such code? My first thought was templates, but I don't yet know how to use them, so as a second thought I got:
FileParser otherFunction() {
ExampleParser ep();
FileParser fp("example.txt", &ep);
return fp;
}
void function() {
FileParser fp = otherFunction(); // countains reference to deleted instance of ExampleParser
}
... but it's also buggy (I showed an edge case purposefully).
What's the proper way to structure that code?
Example use case (as requested below)
auto parser1 = FileParser<SpecificParserType1>(file_name);
parser1.parseFile();
auto parser1.getResults(); // returns instance of specific type 1, e.g. std::vector<Type1>
auto parser2 = FileParser<SpecificParserType2>(file_name);
parser2.parseFile();
auto parser2.getResults(); // returns instance of specific type 2, e.g. std::vector<Type2>
The main goal is to be able to have different strategies of getting data from the file.