【问题标题】:How to report custom istream failures如何报告自定义 istream 故障
【发布时间】:2018-11-18 15:33:30
【问题描述】:

我想使用 operator>>() 从控制台读取线性代数数据。我希望 operator>>() 的行为类似于内置数据(如 int、double),但我也希望在无法解析输入时报告适当的消息。

我终于构建了一个“custom_istream_failure”类,但总的来说还是很麻烦。现在我想知道:这是要走的路,还是为此目的存在另一种机制?这符合标准的精神吗?

我已经包含了一个小型测试程序,它会在“expect”函数中报告自定义失败。此外,我还包含了这个问题所涉及的“custom_istream_failure.h”头文件。

#include <iostream>
#include "custom_istream_failure.h"

struct vector_t { int x, y, z; };

bool expect(std::istream& is, char e)
{
    if (is.get() != e)
    {
        custom_istream_failure(is) 
            << "Expected '" << e << '\'' 
            << and_throw;
        return false;
    }
    return true;
}

std::istream& operator>>(
    std::istream& is, vector_t& v)
{
    expect(is, '(') &&
    (is >> v.x)     &&
    expect(is, ',') &&
    (is >> v.y)     &&
    expect(is, ',') &&
    (is >> v.z)     &&
    expect(is, ')');
    return is;
}

int main()
{
    try
    {
        std::cin.exceptions(std::istream::failbit);
        vector_t vector;
        std::cin >> vector;
    }
    catch (std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

#ifndef CUSTOM_ISTREAM_FAILURE
#define CUSTOM_ISTREAM_FAILURE

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

class custom_istream_failure
    : protected std::stringstream
{
public:
    explicit custom_istream_failure(std::istream& is)
        : m_is(is)
    {}
    custom_istream_failure& operator<<(
        custom_istream_failure& 
            (*pf)(custom_istream_failure&))
    {
        return ((*pf)(*this));
    }
#define CUSTOM_ISTREAM_FAILURE_SOP(D) \
    custom_istream_failure& operator<<(D) \
    { \
        *static_cast<std::stringstream*>(this) << v; \
         return *this; \
    }
    CUSTOM_ISTREAM_FAILURE_SOP(bool v)
    CUSTOM_ISTREAM_FAILURE_SOP(short v)
    CUSTOM_ISTREAM_FAILURE_SOP(unsigned short v)
    CUSTOM_ISTREAM_FAILURE_SOP(int v)
    CUSTOM_ISTREAM_FAILURE_SOP(unsigned int v)
    CUSTOM_ISTREAM_FAILURE_SOP(long v)
    CUSTOM_ISTREAM_FAILURE_SOP(unsigned long v)
    CUSTOM_ISTREAM_FAILURE_SOP(long long v)
    CUSTOM_ISTREAM_FAILURE_SOP(unsigned long long v)
    CUSTOM_ISTREAM_FAILURE_SOP(float v)
    CUSTOM_ISTREAM_FAILURE_SOP(double v)
    CUSTOM_ISTREAM_FAILURE_SOP(long double v)
    CUSTOM_ISTREAM_FAILURE_SOP(void* v)
    CUSTOM_ISTREAM_FAILURE_SOP(std::streambuf* v)
    CUSTOM_ISTREAM_FAILURE_SOP(
        std::ostream& (*v)(std::ostream&))
    CUSTOM_ISTREAM_FAILURE_SOP(
        std::ios& (*v)(std::ios&))
    CUSTOM_ISTREAM_FAILURE_SOP(
        std::ios_base& (*v)(std::ios_base&))
    CUSTOM_ISTREAM_FAILURE_SOP(char v)
    CUSTOM_ISTREAM_FAILURE_SOP(signed char v)
    CUSTOM_ISTREAM_FAILURE_SOP(unsigned char v)
    CUSTOM_ISTREAM_FAILURE_SOP(const char* v)
    CUSTOM_ISTREAM_FAILURE_SOP(const signed char* v)
    CUSTOM_ISTREAM_FAILURE_SOP(const unsigned char*v);
#undef CUSTOM_ISTREAM_FAILURE_SOP
private:
    std::istream& m_is;
    friend custom_istream_failure& and_throw(
        custom_istream_failure&);
};

inline custom_istream_failure& and_throw(
    custom_istream_failure& cif)
{
    try { throw std::ios_base::failure(cif.str()); }
    catch (...)
    { 
        cif.m_is.setstate(std::ios::failbit, true);
    }
    return (cif);
}

#endif // CUSTOM_ISTREAM_FAILURE

【问题讨论】:

    标签: c++ exception customization istream


    【解决方案1】:

    一种方法是让您的类型的输入运算符处理错误条件(下面的示例)。如果用户希望在错误时引发异常,setstate 将触发适当的异常。对于不希望出现异常的用户,只需以通常的方式检查输入流的状态。

    std::istream &operator>>(std::istream &is, vector_t &v) {
        char c;
        if (is >> c && c == '(') {
            int x = 0;
            if (is >> x >> c && c == ',') {
                int y = 0;
                if (is >> y >> c && c == ',') {
                    int z = 0;
                    if (is >> z >> c && c == ')') {
                        v = {x, y, z};
                        return is;
                    }
                }
            }
        }
        is.setstate(std::ios_base::failbit);
        return is;
    }
    

    【讨论】:

    • 使用 std::cin.good() 之类的东西来检查故障位,如果 istream 损坏无法修复则抛出异常
    • @Brandon 为什么不用failbit来检查failbit?
    • Good() 是一种更强的检查,它还检查坏位和 eof 位。 cplusplus.com/reference/ios/ios/good
    • @Brandon 这就是我的观点。 good 会检查更多内容,但如果您只是在寻找 failbit,则应该检查 failbit。在应用程序使用中,您需要知道失败的原因,以便进行适当的恢复。在我的回答中,可能会设置 eof 和 failbit 。如果设置了 eof 那么你知道为什么 failbit 也是。无需尝试其他自定义类型的其他输入。
    • 开始像 Bo R(注意 'and_throw' 中的 'm_is.setstate'),但随后用户收到消息 'ios_base::failbit set: iostream stream error',这不是真正的描述性.例如,当'(' 是预期的,我想自定义消息。它确实有效,但解决方案感觉不必要的大。是否存在更轻的方法?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 2020-05-13
    • 2016-03-24
    • 2014-05-29
    • 2011-04-06
    • 1970-01-01
    相关资源
    最近更新 更多