输入流上基于范围的循环 [英] Range-based loop over an input stream

查看:98
本文介绍了输入流上基于范围的循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要遍历输入流,通常会像这样使用std::istream_iterator:

To iterate over an input stream, we would usually use a std::istream_iterator like so:

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节,添加了粗体):

It'd be nice if we could use the range-based for statement to iterate over input streams. However, for objects of class type, range-based for requires the object to have begin() and end() member functions (§6.5.4, bold emphasis added):

  • 如果_RangeT是数组类型,则 begin-expr end-expr 分别是__range__range + __bound,其中是数组绑定.如果_RangeT是未知大小的数组或类型不完整的数组,则程序格式错误;

  • if _RangeT is an array type, begin-expr and end-expr are __range and __range + __bound, respectively, where __bound is the array bound. If _RangeT is an array of unknown size or an array of incomplete type, the program is ill-formed;

如果_RangeT是类类型,则在不合格ID beginend >好像按类成员访问查找(3.4.5),并且如果一个(或两个)都找到至少一个声明,则 begin-expr end-expr __range.begin()__range.end()分别;

if _RangeT is a class type, the unqualified-ids begin and end are looked up in the scope of class _RangeT as if by class member access lookup (3.4.5), and if either (or both) finds at least one declaration, begin-expr and end-expr are __range.begin() and __range.end(), respectively;

否则, begin-expr end-expr 分别为begin(__range)end(__range),其中beginend与参数相关的查找(3.4.2).出于此名称查找的目的,名称空间std是关联的名称空间.

otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace.

输入流不具有这些成员函数(它们不是Container),因此基于范围的for不适用于它们.无论如何,这是有道理的,因为您将需要某种方式来指定要提取的类型(在上述情况下为std::string).

The input streams don't have these member functions (they are not Containers) and so range-based for won't work on them. This makes sense anyway because you would need some way to specify the type to extract (std::string in the case above).

但是,如果我们知道要提取的内容,是否可以为输入流定义我们自己的begin()end()函数(也许是std::begin()std::end()的特殊化或重载),以便如上所述由类成员访问查找找到?

But if we know what we want to extract, is it possible to define our own begin() and end() functions (perhaps specializations or overloads of std::begin() and std::end()) for input streams such that they would be found by class member access lookup as described above?

从6.5.4节开始(至少对我而言)尚不清楚,如果先前的查找失败,那么是否将使用依赖于参数的查找来查找函数.要考虑的另一件事是,std::ios_base及其派生词已经有一个名为end的成员,该成员是进行搜索的标志.

It's unclear (at least to me) from §6.5.4 whether the functions will then be looked up with argument-dependent lookup if the previous lookup fails. Another thing to consider is that std::ios_base and its derivatives already have a member called end which is a flag for seeking.

这是预期的结果:

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
}

推荐答案

一种显而易见的方法是为流使用简单的装饰器,以提供类型和必要的接口.这是这样的样子:

An obvious approach is to use a simple decorator for your stream providing the type and the necessary interface. Here is how this could look like:

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)) {
    ...
}

这篇关于输入流上基于范围的循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆