要遍历输入流,通常会使用std::istream_iterator,如下所示:

typedef std::istream_iterator<std::string> input_iterator;

std::ifstream file("myfile");
for (input_iterator i(file); i != input_iterator(); i++) {
  // Here, *i denotes each element extracted from the file
}
如果我们可以使用基于范围的for语句来迭代输入流,那将是很好的。但是,对于类类型的对象,基于范围的for要求该对象具有begin()end()成员函数(第6.5.4节,添加了粗体):

输入流没有这些成员函数(它们不是Container),因此基于范围的for将无法在它们上工作。无论如何,这是有道理的,因为您将需要某种方式来指定要提取的类型(在上述情况下为std::string)。
但是,如果我们知道要提取的内容,是否可以为输入流定义我们自己的begin()end()函数(也许是std::begin()std::end()的特殊化或重载),以便可以通过如上所述的类成员访问查找找到它们?
从§6.5.4尚不清楚(至少对我而言),如果先前的查找失败,那么是否将使用依赖于参数的查找来查找函数。要考虑的另一件事是std::ios_base及其派生类已经具有一个称为end的成员,该成员是用于查找的标志。
这是预期的结果:
std::ifstream file("myfile");
for (const std::string& str : file) {
  // Here, str denotes each element extracted from the file
}
或者:
std::ifstream file("myfile");
for (auto i = begin(file); i != end(file); i++) {
  // Here, *i denotes each element extracted from the file
}

最佳答案

一种明显的方法是为您的流使用一个简单的装饰器,以提供类型和必要的接口(interface)。这是这样的:

template <typename T>
struct irange
{
    irange(std::istream& in): d_in(in) {}
    std::istream& d_in;
};
template <typename T>
std::istream_iterator<T> begin(irange<T> r) {
    return std::istream_iterator<T>(r.d_in);
}
template <typename T>
std::istream_iterator<T> end(irange<T>) {
    return std::istream_iterator<T>();
}

for (auto const& x: irange<std::string>(std::ifstream("file") >> std::skipws)) {
    ...
}

关于c++ - 输入流上基于范围的循环,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13037490/

10-09 16:37