如何返回各种类型的可变数量的容器?

时间:2012-05-01 20:29:16

标签: c++ boost generic-programming boost-mpl boost-variant

我的数据如下:

     token            eps  rank # first line names columns
 Intercept   9.362637e+00     1 # later lines hold data
        A1  -2.395553e-01    30
        G1  -3.864725e-01    50
        T1   1.565497e-01    43
....

不同的文件将具有不同数量的命名列,并且每列中的值类型将在浮点数,整数和字符串之间变化。

我想写一个readCols函数,我发送列的名称(例如,我可能想要tokenrank列),这些列将把数据放在指定的列中进入适当类型的容器。

我的问题不是解析文件,而是返回包含不同类型的可变数量的容器。例如,我希望tokenrank列分别放入vector<string>vector<int>容器中。这里的问题是我可能想要eps列(存储在向量中),并且我不想为每种可能的类型组合编写不同的readCols函数。 (容器的类型对我来说无关紧要。如果我只需要使用vector,没问题;每个容器包含不同的类型是关键。)

我可能需要一个容纳不同类型的容器来容纳不同类型的容器。看起来Boost.Variant可能是我想要的解决方案,但我不知道如何告诉解析器我想要每个列的类型(我可以创建类似名称的列表吗?例如{{1} })。同样地,Boost.Mpl.Vector可以解决问题,但我再也无法确定如何告诉void readCols(string filename, vector<variant<various types of vector>> &data, vector<string> colNames, vector<typename> convertTo)每列想要如何投射。

我至少可以考虑两种解决方法:

  1. 使用模板化函数分别读取每一列,该函数读入任何容器(readCols允许函数知道如何解析)。我不喜欢这个解决方案,因为文件偶尔很大(数百万行),因此多次解析它们需要额外的几分钟(在计算需要约30分钟的程序中,运行时间的百分比可以忽略不计;程序将一遍又一遍地跑。)
  2. 将所有列读入字符串容器,并在调用上下文中重新转换它们,而不是在解析上下文中。这不会那么糟糕,因为我认为我可以使用container::value_typestd::transform或s / t在一行中进行转换。如果我可以避免boost::lexical_cast行膨胀,那么(2n =列数通常为2或3,每列2行以声明容器然后进行转换)。
  3. 可能第二种解决方法需要的工作量比完整的通用解决方案要少得多;如果是这样的话,我想知道。我想第二种解决方法甚至可能更有效,但我主要关注的是目前的易用性。如果我可以编写一个通用n函数并完成它,那就是我更喜欢的。

2 个答案:

答案 0 :(得分:1)

当事情变得太复杂时,我将问题分解成更小的部分。所以这是一个建议。

编写一个CSV阅读器类,它可以从文件中读取逗号或其他分隔符分隔值。该类一次读取一行并将该行拆分为std :: string字段。为了访问这些字段,您可以实现访问字段(按列名或索引)的getString,getInt,getDouble等函数,并将它们转换为适当的类型。因此,读者做了一个定义明确的事情,并处理有限数量的原始类型。

然后实现使用CSV阅读器的阅读器功能(或类)。这些读者函数知道列的特定类型以及放置值的位置 - 在标量,容器等中。

答案 1 :(得分:0)

只要返回值的类型有限,例如intdoublestd::string,这样的功能可以完成这项工作:

using namespace std;
void readCols(string fileName, vector<string> stringCols, 
      vector<string> intCols, vector<string> doubleCols, 
      vector<vector<string> > *stringData, 
      vector<vector<int> > *intData, 
      vector<vector<double> > *doubleData);

(可能很清楚,但你根据它们的类型列出了你想要的列名。)

这种解决方案是否比解决方案更多或更少是在旁观者的眼中。