输入流上基于范围的循环

Jos*_*eld 8 c++ iterator inputstream c++11

要迭代输入流,我们通常会使用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
}
Run Code Online (Sandbox Code Playgroud)

如果我们可以使用基于范围的for语句来迭代输入流,那就太好了.但是,对于类的对象,范围为基础的for需要的对象具有begin()end()成员函数(§6.5.4,粗体强调):

  • 如果_RangeT是一个数组类型,开始-EXPR最终EXPR__range__range + __bound分别,其中__bound在阵列的约束.如果_RangeT是未知大小的数组或不完整类型的数组,则该程序格式不正确;

  • 如果_RangeT是一个类型时,不合格的IDS begin并且end在类的范围查找_RangeT仿佛由类成员访问查找(3.4.5),并且如果任一个(或两者)找到至少一个声明,开始-EXPR端-expr分别是__range.begin()__range.end();

  • 否则,开始-EXPR最终EXPRbegin(__range)end(__range)表示,其中beginend被查找与参数相关的查找(3.4.2).出于此名称查找的目的,namespace std是关联的命名空间.

输入流没有这些成员函数(它们不是容器),因此基于范围的函数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
}
Run Code Online (Sandbox Code Playgroud)

要么:

std::ifstream file("myfile");
for (auto i = begin(file); i != end(file); i++) {
  // Here, *i denotes each element extracted from the file
}
Run Code Online (Sandbox Code Playgroud)

Die*_*ühl 6

一个显而易见的方法是为您的流使用一个简单的装饰器,提供类型和必要的接口。这可能是这样的:

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)) {
    ...
}
Run Code Online (Sandbox Code Playgroud)


Set*_*gie 1

是否可以通过参数相关的查找找到它们并不重要,因为您可以将类和函数的特化放在std命名空间中。