I want to read and parse a text file in C++ in a generic way. The file is always made of key-value pairs, one per line. The key is templated as well as the value. I foresee the key and the values to always be a basic type (int, float, string).
My problem is that I don’t know how to create a transform the key or value string into the correct type.
I tried the following :
template<class Key, class T> inline
void EventReportReader<Key, T>::validateFileFormat()
{
// Read file line by line and check that the first token is of type Key and the second one of type T
std::string line;
try {
boost::regex re( "(\\S+)\\s+(.*)" );
while( getline( inStream_, line ) ) {
boost::cmatch matches;
if( boost::regex_match( line.c_str(), matches, re ) ) {
std::cout << re << " matches " << line << std::endl;
std::cout << " 1st : " << matches[1] << "\n 2nd : " << matches[2] << std::endl;
// test types
Key *k = dynamic_cast<Key*>(&matches[1]);
T t = dynamic_cast<T>(matches[2]);
}
}
}
catch( boost::regex_error& e ) {
// todo problem with regular expression, abort
}
}
And the use of this method is as follow :
// This in turn calls the method validateFileFormat
EventReportReader<float, int> reader( testFileName );
The result is
/home/vonhalle/dev/EventBasedReport/libs/event_based_report/EventReportReader.h:121:60: error: cannot dynamic_cast ‘(const boost::sub_match*)matches.boost::match_results::operator[] with BidiIterator = const char*, Allocator = std::allocator >, boost::match_results::const_reference = const boost::sub_match&’ (of type ‘const struct boost::sub_match’) to type ‘float’ (target is not pointer or reference to class)
/home/vonhalle/dev/EventBasedReport/libs/event_based_report/EventReportReader.h:122:53: error: cannot dynamic_cast ‘matches.boost::match_results::operator[] with BidiIterator = const char*, Allocator = std::allocator >, boost::match_results::const_reference = const boost::sub_match&’ (of type ‘const struct boost::sub_match’) to type ‘int’ (target is not pointer or reference)
How should I do it ?
Is it even possible ?
EDIT:
The file might look like this if the template is < float, int >
1.14 5
2.34 78
0.56 24
or this if the template is < int, string >
23 asdf
45 2222
1 bbbb
EDIT2:
The problem statement above is partially wrong. The key is never a string, the value can be a string. Therefore, whatever is before the first space is the key and the rest is the value. Sorry about this mistake.
I think your basic approach is wrong.
You seem to be trying to use template-meta programming to achieve your goals.
This is probably not a good idea.
A simpler approach is just to use C++ streams.
These stream objects already know how to read all the basic types. And anybody that want to do anything in C++ will add the appropriate input and output operators to stream their class; so it is pretty universal that you will be able to read any type as both key and value (with the restriction that it must fit on one line).
So now you just need to use standard template logic to define an operator that will read two objects of different types on a single line.
Try this:
Here is the code that will read one record from one line of the file:
Note that the data type
Dataand this input operator are both templated and can thus ready Key/Value pairs of any objects (as long as those objects know how to stream themselves).Now using it simply means using a stream:
Note: In the above example a key must be a single word (as it is read using a string). If you want a key as a string that contains a space you need to do some extra work. But that is the subject of another question.