在C++中将整数从文件读入向量

8
我试图从文本文件中的单独行中读取未知数量的双精度值到名为rainfall的向量中。我的代码无法编译,我得到了错误信息no match for 'operator>>' in 'inputFile >> rainfall'在while循环行中。我知道如何将文件读入数组,但是我们需要在此项目中使用向量,而我还不太懂它。我很感谢您在下面的部分代码上给出的任何提示。
vector<double> rainfall;    // a vector to hold rainfall data

// open file    
ifstream inputFile("/home/shared/data4.txt");

// test file open   
if (inputFile) {
    int count = 0;      // count number of items in the file

    // read the elements in the file into a vector  
    while ( inputFile >> rainfall ) {
        rainfall.push_back(count);
        ++count;
    }

    // close the file

2
我建议使用迭代器对构造函数。网上有很多例子。 - chris
5个回答

17

我认为你应该将其存储到 double 类型的变量中。看起来你正在对一个向量进行 >> 操作,这是无效的。考虑以下代码:

// open file    
ifstream inputFile("/home/shared/data4.txt");

// test file open   
if (inputFile) {        
    double value;

    // read the elements in the file into a vector  
    while ( inputFile >> value ) {
        rainfall.push_back(value);
    }

// close the file

正如 @legends2k 指出的那样,您不需要使用变量 count。可以使用 rainfall.size() 来检索向量中的项目数。


此外,变量 count 是多余的,因为 rainfall.size() 可以提供这些信息。 - legends2k

13

您不能使用>>运算符一次读取整个向量。您需要逐个读取每个项,并将其推入向量中:

您需要逐个读取每个项,并将其推入向量中,无法使用>>运算符一次性读取整个向量。

double v;
while (inputFile >> v) {
    rainfall.push_back(v);
}

你不需要计算元素数量,因为rainfall.size()可以给出确切的数量。

最后,使用istream迭代器是C++中最典型的读取vector的方法:

// Prepare a pair of iterators to read the data from cin
std::istream_iterator<double> eos;
std::istream_iterator<double> iit(inputFile);
// No loop is necessary, because you can use copy()
std::copy(iit, eos, std::back_inserter(rainfall));

我正在根据上面一位发帖者的建议研究迭代器概念。目前对我来说有点复杂,但我决心要理解这些东西!再次感谢大家的帮助。 - user2922063

10
您也可以这样做:
#include <algorithm>
#include <iterator>

...
std::istream_iterator<double> input(inputFile);
std::copy(input, std::istream_iterator<double>(),    
          std::back_inserter(rainfall));
...

假设您喜欢STL。

6

输入运算符>>未定义用于将double输入到std::vector中。

相反,使用两个标记化的输入迭代器为输入文件构造std::vector

以下是如何仅使用2行代码完成此操作的示例:

std::ifstream inputFile{"/home/shared/data4.txt"};
std::vector<double> rainfall{std::istream_iterator<double>{inputFile}, {}};

另一个解决方案是将输入运算符函数定义为:
std::istream& operator>> (std::istream& in, std::vector<double>& v) {
    double d;
    while (in >> d) {
        v.push_back(d);
    }
    return in;
}

然后,您可以像您的示例一样使用它:
std::vector<double> rainfall;
inputFile >> rainfall;

感谢您展示第一种方法。是的,只有2行代码,但我认为它不够易读。不太明显正在发生什么。第二个参数是什么?它调用了向量的构造函数,该构造函数接受两个输入迭代器和一个可选分配器。第二个输入迭代器似乎是默认构造的,并指向空(NULL)。这种行为是否标准确认/定义在某个地方?如何回答这些问题? - SebastianWilke
@SebastianWilke 当在此情况下使用{}而没有类型时,它将被视为类型推断的值或直接初始化(取决于是否提供了参数)的值,因此在这种情况下,它等同于std::istream_iterator<double> {}。对std::istream_iterator进行值初始化会产生流结束迭代器(请参见此处)。 - Felix Glas
@SebastianWilke 我找不到关于{}无类型工作的适当规范参考,但通常称为“统一初始化”。对于流结束迭代器使用值初始化(空括号)是标准用法(例如,请参见示例)。例如:for_each(std::istream_iterator<double>(my_istream), std::istream_iterator<double>())将迭代my_istream直到达到流结束。 - Felix Glas

2
请考虑使用这个输入读取器:
#include <iterator>
#include <algorithm>
#include <vector>
#include <iostream>
#include <fstream>

template<typename T>
std::vector<T> parse_stream(std::istream &stream) {
    std::vector<T> v;
    std::istream_iterator<T> input(stream);
    std::copy(input, std::istream_iterator<T>(), std::back_inserter(v));
    return v;
}

int main(int argc, char* argv[])
{
    std::ifstream input("/home/shared/data4.txt");
    std::vector<int> v = parse_stream<int>(input);
    for(auto &item: v) {
        std::cout << item << std::endl;
    }
    return 0;
}

它允许您使用其他流类型,并且对读取类型具有通用性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接