2

我有以下形式的序列号类:

class SerialNumber { ... }

我想operator>>为它写:

istream& operator>>(istream& i, SerialNumber& s)
{
    ???

    return i;
}

序列号的长度始终为 19 个字符,并以十六进制数字开头。

如果我应该istream.read19 个字符,我很困惑。它可能包括前缀空格。?

或者我是否应该阅读 ai >> std::string然后检查它是否有 19 个字符长。当您阅读 astd::string时,它会跳过空格(是否有标准的方法来实现?)此外,如果我阅读 astd::string它可能有一个有效的 19 个字符的序列号前缀,我可能会“过度阅读”输入。?

更新:

inline istream& operator>>(istream& is, SerialNumber& id)
{
    ostringstream os;

    is >> ws;

    for (int i = 0; i < 19; i++)
    {
        char c;
        is >> c;
        os << c;
    }

    id = DecodeId(os.str());

    return is;
}

Dietmar Kühl 代码的部分净化版本:

istream& operator>> (istream& in, SerialNumber& sn)
{
    constexpr size_t n = 19;

    istream::sentry se(in);

    if (!se)
        return in;

    istreambuf_iterator<char> it(in.rdbuf()), end;

    if (it == end || !isxdigit(*it))
    {
        in.setstate(ios_base::failbit);
        return in;
    }

    string s(n,'?');
    for (size_t i = 0; it != end && i < n && !isspace(char(*it)), ++i)
            s[i] = *it++;

    sn = DecodeId(s);

    if (failed to decode)
        in.setstate(ios_base::failbit);

    return in;
}
4

2 回答 2

3

标准格式的输入函数始终遵循相同的模式:

  1. 他们从构造一个std::sentry对象开始,该对象根据std::ios_base::skipws格式化标志的设置处理前导空格的任何跳过。
  2. 如果读取值以任何方式失败std::ios_base::failbit并被设置,则读取值不变。
  3. 字符被消耗到第一个与格式不匹配的字符。

也就是说,输入函数看起来像这样:

std::istream& operator>> (std::istream& in, SerialNumber& s) {
    std::istream::sentry kerberos(in);
    if (kerberos) {
        std::istreambuf_iterator<char> it(in.rdbuf()), end;
        char buffer[20] = {};
        int  i(0);
        if (it != end && std::isxdigit(static_cast<unsigned char>(*it))) {
            for (; it != end && i != 19
                   && !std::isspace(static_cast<unsigned char>(*it)); ++i) {
                buffer[i] = *it++;
            }
        }
        if (i == 19) {
            SerialNumber(buffer).swap(s);
        }
        else {
            in.setstate(std::ios_base::failbit);
        }
    }
    return in;
}
于 2012-12-27T06:19:48.447 回答
1

你应该一次做一步:

  • 如果您想始终跳过空格,请先执行i >> std::ws. 流可能没有skipws设置标志。否则让用户决定是否跳过空白,并在读取空白时设置流错误位。

  • 阅读第一个char,看看它是否是十六进制数字。如果不是,则设置流错误位。

  • 读取剩下的 18 个字符,一旦发现不符合序列号格式的字符,就设置流错误位。

    您应该禁用skipws此功能,否则您将从由空格分隔的字符中获得有效结果。如果这样做,请确保skipws在退出函数时恢复标志(如果在流上启用了异常,则在设置错误位时可能会通过异常发生)。

于 2012-12-27T05:58:23.430 回答