设置流状态以在格式化输出运算符 (operator<<) 中传达错误

Set stream state to communicate error in formatted output operator (operator<<)

我认为最佳做法是在给定输入不可用时在输入流上设置故障位。但是我想知道为什么我找不到在 ostream 上做同样事情的证据。

例如 cppreference 有以下重载操作符 << 和 >> 的例子。

std::ostream& operator<<(std::ostream& os, const T& obj)
{
    // write obj to stream
    return os;
}
std::istream& operator>>(std::istream& is, T& obj)
{
    // read obj from stream
    if( /* T could not be constructed */ )
        is.setstate(std::ios::failbit);
    return is;
}

问题:我想知道是否还应该在输出流上设置故障位(如果适用)。

请考虑以下示例:

enum class enumeration
{
    ONE,
    TWO
};

std::ostream& operator<<(std::ostream& os, const enumeration& e)
{
    switch (e)
    {
        case enumeration::ONE:
            os << "1";
            break;
        case enumeration::TWO:
            os << "2";
            break;
        default: 
            os.setstate(std::ios::failbit); // <-- line in question
            break;
    }
    return os;
}

该行是否合理? (我在这里放了一个工作示例 cpp.sh。)

最后我想知道我是否可以、应该或避免在 ostream 上设置 failbit 以及为什么。

您所描述的案例的标准做法是编写一些无效值的表示形式。通常不需要将其标记为错误。例如,如果出现数值 42,您可以写“? (42)”。或者可能只是“42”,如果您希望能够使用 operator >>.

轻松地将文本返回到枚举

只是从评论中总结我的结论(感谢一些程序员的输入)...

您将两个问题混为一谈,最好分开:

a) 枚举值可能无效

b) 流式传输到 os 可能会失败

可以说 a) 并不真正属于 operator<< 重载。如果您想确保枚举有效,那么您可能还想在其他地方检查它,而不仅仅是在流式传输时。实际上你应该在之前这样做,以便能够尽快检测到错误,而不仅仅是当它到达 user/outside 世界时。另一方面,从我的头顶上我不知道如何使用范围枚举到达 default 除非你故意尝试做错事。在那种情况下,你只会得到你应得的。不要过度保护。

对于 b),您不需要在代码中做任何额外的事情。如果

 os << "1";

确实失败了,那么这个调用已经为你设置了失败位。

TL;DR:您可能不需要 operator<< 中的检查。如果您认为需要检查,那么 operator<< 仍然不是放置它的正确位置。