如何报告自定义istream失败

时间:2018-11-18 15:33:31

标签: c++ exception customization istream

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

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

我包含了一个小型测试程序,该程序报告了“期望”功能中的自定义失败。此外,我还包含了这个问题所在的“ 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

1 个答案:

答案 0 :(得分: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;
}