C ++流提取运算符重载

时间:2015-06-03 18:40:53

标签: c++ overloading operator-keyword

这是关于用户编写的C ++输入流提取运算符(>>)的哲学(规范设计)的问题。

假设在进入>>时运算符实现(对于用户编写的类),已经为输入流设置了eof标志。

用户编写的提取运算符(>>)

  1. 设置失败标志(因为找不到所需对象的实例)
  2. 应该只返回调用者,并且仍然设置了eof标志。
  3. 如果使用第二种方法,则意味着在尝试调用>>之前,调用者必须始终检查eof标志。运营商。原因是>> operator可能会成功提取所需类的实例并设置eof标志。

    原始代码如下。根据以下评论,此代码似乎是错误的。如果已经在输入上设置了eof,则提取操作符将仅在eof仍然设置的情况下返回。看来如果设置了eof,但是没有设置bad和fail,那么应该提取字符串来设置失败位。当然,可以直接设置失败位。

    /* Implement the C/C++ >> (stream input) operator as a non-member 
       function */
    std::istream &operator>>(std::istream& is, DecNumber &val) {
      DecContext  context{DecContext::defInit};
      uint32_t    status;
      /* The true value below prevents whitespace from being skipped */
      std::istream::sentry  s(is, true);
      std::string           inStr;
      /* Check if the input stream is in a good state. Just return to the
         caller if the input stremm is not in a good state. The caller
         must handle this condition. */
      if(!s) 
        return is; 
      /* Get a string from the input stream. This string is converted to 
         a DecNumber below. Just return to the caller if this step causes
         any stream related errors. Note that reaching the end of the 
         input is not a stream related error here. A decimal number might
         be the absolute last thing in the stream. */
      is >> inStr;
      if (is.bad() || is.fail())
        return is;
      /* Try to convert the string to a DecNumber using the default context
         value */
      decNumberFromString(val.getDecVal(), inStr.c_str(), context.getDecCont());
      status = context.DecContextGetStatus();
      /* Remove a few status bits we don't care about */
      status &= ~(DEC_Inexact + DEC_Rounded);
      if (status)
        is.setstate(std::ios_base::failbit); 
      return is;
    }
    

2 个答案:

答案 0 :(得分:1)

  

"如果使用第二种方法,则意味着调用者必须始终检查eof标志,然后才会尝试调用>>操作员"

不,你为什么认为他们需要这样做?

  

"用户编写的提取运算符(>>)是否应该设置失败标志(因为找不到所需对象的实例),或者它应该只是通过eof返回给调用者国旗仍然设置。"

后一种选择当然,除非您添加自己的验证规则(例如,期望具有model = word2vec.Word2Vec.load_word2vec_format('/tmp/vectors.bin', binary=True) 字段的特定字符模式),否则您不应该在重载的提取运算符中管理流状态。它通常可以通过重载运算符使用的子提取操作正确完成。

假设你有以下内容:

std::string

如果struct MyType { std::string field1; int field2; double field3; } std::istream& operator>>(std::istream& is, MyType& myinstance) { is >> field1; is >> field2; is >> field3; return is; } 失败,每个提取都会将字段设置为默认的构造值,因为流处于operator>>()状态,并且值将保留在其中{&1;}尝试提取的字段的原始状态。

我实际上没有看到需要对eof()进行任何额外检查,或者在重载的输入操作符中将流设置为eof()状态。

客户(来电者)只会使用类似的东西。

fail()

您看,无需在任何地方检查 std::ifstream input("MyFile.txt"); std::vector<MyType> allObjects; MyType curObject; while(input >> curObject) { allObjects.push_back(curObject); }

答案 1 :(得分:1)

您应该实施解决方案1.

如果有疑问,只需看看已经完成的工作。如下所示,如果我们尝试从EOF状态的流中读取,则会设置失败位。

请注意,EOF并不是失败的唯一方法。请尝试在下面的代码中设置std::string vals = "52 43 A";

如果因任何原因,则应设置

failbitoperator>>实际上不会传输值。 EOF只是其中一个原因。

#include <sstream>
#include <iostream>
#include <string>

void print_stream (std::istream & print_me, int const & i)
{
  std::cout << "i: " << i << "\n";
  std::ios_base::iostate bits = print_me.rdstate();

  std::cout << "good: " << (bits & std::ios_base::goodbit) << 
    ", bad: " << (bits & std::ios_base::badbit) << 
    ", fail: " << (bits & std::ios_base::failbit) <<
    ", eof: " << (bits & std::ios_base::eofbit) << "\n";

  std::cout << "\n----------------------------\n\n";
}

int main (void)
{
  std::string vals = "52 43";
  std::istringstream iss(vals);
  int i;

  iss >> i;
  print_stream (iss, i);
  iss >> i;
  print_stream (iss, i);
  iss >> i;
  print_stream (iss, i);
  iss >> i;
  print_stream (iss, i);

  return 0;
}

输出

$ ./a.exe
i: 52
good: 0, bad: 0, fail: 0, eof: 0

----------------------------

i: 43
good: 0, bad: 0, fail: 0, eof: 2

----------------------------

i: 43
good: 0, bad: 0, fail: 4, eof: 2

----------------------------

i: 43
good: 0, bad: 0, fail: 4, eof: 2

----------------------------

请注意,典型的读取模式循环是......的一些变体。

while (input >> var >> var2 >> var3)
{
  // failbit is not set.  All reads succeeded.
  // Do Stuff
}

如果你需要检测在读取多个值的过程中是否发生了故障,那么你需要做一些更复杂的测试并做一些测试...

while (true)
{
  if (input >> var)
  {
    // We successfully read first value
    if (input >> var2 >> var3)
    {
      // We succesfully read all the values!
      // Do stuff
    }
    else
    {
      ErrorLog ("Partial line read!");
      break;
    }
  else
  {
    // Nothing else to read
    break;
  }
}