【问题标题】:Reading file line by line WITHOUT using FOR/WHILE loop不使用 FOR/WHILE 循环逐行读取文件
【发布时间】:2013-03-28 04:36:24
【问题描述】:

大家好,这对你们来说是一个有趣的挑战。 我得到了一个文本文件,我应该逐行处理信息。只要我能获得单独的线条,处理部分就很简单。然而,挑战在于:

  1. 我必须这样做,而不要在我的代码中使用任何 FOR/WHILE 循环。 (这包括递归)
  2. 我只能使用标准 C++ 库。

目前我最好的解决方案是: Is there a C++ iterator that can iterate over a file line by line? 但我希望有一个更好的,不涉及创建我自己的迭代器类或为 std::string 实现代理。

附:这是一个学校作业,这里的挑战是使用标准功能和算法的组合来解决问题,但我不知道如何解决它

【问题讨论】:

  • 为什么不能使用forwhile 循环?
  • 这很没有意义,如果您逐行解析某些内容,您实际上是在循环文件
  • 有这种愚蠢的要求,goto 是最好的选择。
  • 它实际上是为了学校作业。这里的挑战是尝试使用标准库算法和功能的组合来完成分配,但我不知道如何去做

标签: c++ file c++11 iterator


【解决方案1】:
ifstream input("somefile")

if (!input) { /* Handle error */ }

//MyDataType needs to implement an operator>>

std::vector<MyDataType> res;

std::istream_iterator<MyDataType> first(input);
std::istream_iterator<MyDataType> last;
std::copy(first,last, std::back_inserter(res));

//etc..

您的输入运算符可以是这样的:

std::istream& operator>>(std::istream &in,MyDataType & out)
{
    std::string str;
    std::getline(in,str);
    //Do something with str without using loops
    return in;
}

这里有很多循环(你不想用goto,不是吗?),但它们都隐藏在std::copystd::getline后面

【讨论】:

  • 你不是说operator &gt;&gt;吗?
  • 这实际上与我发布的链接中的答案非常相似,如果我找不到任何东西,我会把它作为最后的手段
  • @Angew zzz.. 抱歉我修好了
  • @sbabbi 有正确的方向。他也可以重载std::find,但我对它不够熟悉,无法提供示例。
【解决方案2】:

这只是一个玩具。

它包含一个基于生成器的方式来获取文件(我觉得这很容易编写),以及一个将生成器转换为迭代器的半工作适配器。

在此上下文中的生成器是一个函子,它接受一个 lambda,并将该 lambda 传递给迭代的事物并返回 true,或者返回 false。它形成了一个非常短的循环:

while( gen( [&]( std::string line ) {
  // code using line goes here
} ) ); // <- notice that this is an empty while loop that does stuff

但你不能使用它。 (这个设计的灵感来自于 python 生成器,老实说,我发现它比 C++ 迭代器更自然地处理多种问题,包括从文件中读取)。

adpator 接受这个生成器并将其变成一个迭代器,所以你可以将它传递给for_each

重点是你的问题本身是空洞的,所以与其做一些明显的事情(转到,或直接在 istream 迭代器上使用for_each),我建议搞乱一些迟钝和不同的东西。 :)

Line 生成器又好又短:

struct LineGenerator {
  LineGenerator(std::ostream& os_):os(&os_) {}
  std::ostream* os;
  template<typename F>
  bool operator()(F&& func) {
    std::string s;
    bool bRet = std::getline( *os, s );
    if (!bRet) return false;
    std::forward<F>(func)(s);
    return true;
  }
};

另一方面,适配器相当混乱:(并且未经测试)

template<typename Generator>
struct generator_iterator {
  typedef generator_iterator<Generator> my_type;
  typedef typename std::decay< decltype( std::declval<Generator>()() ) >::type value_type;
  Generator g;
  bool bDone;
  value_type val;
  generator_iterator( Generator g_ ):g(g_), bDone(false) {
    next();
  }
  generator_iterator(): bDone(true) {}
private:
  void next() {
    if (bDone) return;
    bDone = g(val);
  }
public:
  generator_iterator& operator++() {
    next();
    return *this;
  }
  value_type operator*() {
    return val;
  }
  const value_type operator*() const {
    return val;
  }
  value_type* operator->() {
    return &val;
  }
  value_type const* operator->() const {
    return &val;
  }
  bool operator==( my_type const& o ) {
    if (bDone != o.bDone) return false;
    if (!bDone && !o.bDone) return true;
    return false;
  }
};
template<typename Generator>
generator_iterator<Generator> make_gen_it( Generator&& g ) {
  return generator_iterator<Generator>( std::forward<Generator>(g) );
}
template<typename Generator>
generator_iterator<Generator> make_end_gen_it() {
  return generator_iterator<Generator>();
}

我希望这很有趣!

【讨论】:

    猜你喜欢
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 2018-04-17
    • 2015-04-26
    • 2011-12-04
    • 2013-04-26
    • 1970-01-01
    相关资源
    最近更新 更多