Bar*_*rth 5 c++ parsing templates type-conversion
我想以通用方式阅读和解析C ++中的文本文件。该文件始终由键值对组成,每行一对。键和值都是模板化的。我预见到键和值始终是基本类型(int,float,string)。
我的问题是我不知道如何创建将键或值字符串转换为正确类型的方法。
我尝试了以下方法:
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
}
}
Run Code Online (Sandbox Code Playgroud)
并且此方法的用法如下:
// This in turn calls the method validateFileFormat
EventReportReader<float, int> reader( testFileName );
Run Code Online (Sandbox Code Playgroud)
结果是
/home/vonhalle/dev/EventBasedReport/libs/event_based_report/EventReportReader.h:121:60:错误:无法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&'(类型为'const struct boost :: sub_match ')类型为'float '(目标不是指针或对类的引用) )/home/vonhalle/dev/EventBasedReport/libs/event_based_report/EventReportReader.h:122:53:错误:无法dynamic_cast'matches.boost :: match_results :: operator [] with BidiIterator = const char *,Allocator = std ::分配器>,boost :: match_results :: const_reference = const boost :: sub_match&'(类型为'const struct boost :: sub_match')类型为'int'(目标不是指针或引用)
我该怎么办?可能吗?
编辑: 如果模板为<float,int>,则文件可能看起来像这样
1.14 5
2.34 78
0.56 24
Run Code Online (Sandbox Code Playgroud)
或如果模板为<int,string>
23 asdf
45 2222
1 bbbb
Run Code Online (Sandbox Code Playgroud)
编辑2:
上面的问题陈述部分是错误的。密钥永远不能是字符串,值可以是字符串。因此,第一个空格之前的内容是键,其余部分是值。对不起,这个错误。
我认为您的基本做法是错误的。
您似乎正在尝试使用模板元编程来实现您的目标。
这可能不是一个好主意。
一个更简单的方法就是使用C ++流。
这些流对象已经知道如何读取所有基本类型。任何想用C ++做任何事情的人都将添加适当的输入和输出运算符以流式传输他们的类。因此,您可以读取任何类型的键和值,这是非常普遍的(限制条件是它只能放在一行上)。
因此,现在您只需要使用标准模板逻辑来定义一个运算符,该运算符将在一行上读取两个不同类型的对象。
尝试这个:
#include <string>
#include <memory>
#include <fstream>
#include <sstream>
#include <vector>
#include <iterator>
#include <algorithm>
// These can be any types.
typedef std::string Key;
typedef int Value;
// The data type to hold the data.
template<typename K,typename V>
class Data: public std::pair<K, V>
{
};
Run Code Online (Sandbox Code Playgroud)
这是从文件的一行读取一条记录的代码:
请注意,数据类型Data和此输入运算符都是模板化的,因此可以准备任何对象的键/值对(只要这些对象知道如何流式传输自己) )。
template<typename K,typename V>
std::istream& operator>>(std::istream& stream, Data<K,V>& data)
{
// Read a line into a local string.
std::string line;
std::getline(stream,line);
// convert the line into a stream and read the key/value from the line
std::stringstream linestream(line);
linestream >> data.first >> data.second;
// If the linestream is bad, then reading the key/value failed
// If reading one more `char` from the linestream works then there is extra crap in the line
// thus we have bad data on a line.
//
// In either case set the bad bit for the input stream.
char c;
if ((!linestream) || (linestream >> c))
{
stream.setstate(std::ios::badbit);
}
// return the stream.
return stream;
}
Run Code Online (Sandbox Code Playgroud)
现在使用它只是意味着使用流:
int main()
{
// The input file
std::ifstream file("Plop");
// We will convert the file and store it into this vector.
std::vector<Data<Key,Value> > data;
// Now just copy the data from the stream into the vector.
std::copy(std::istream_iterator<Data<Key,Value> >(file),
std::istream_iterator<Data<Key, Value> >(),
std::back_inserter(data)
);
}
Run Code Online (Sandbox Code Playgroud)
注意:在上面的示例中,键必须是一个单词(因为它是使用字符串读取的)。如果要将键作为包含空格的字符串作为字符串,则需要做一些额外的工作。但这是另一个问题的主题。
| 归档时间: |
|
| 查看次数: |
9140 次 |
| 最近记录: |