mercredi 26 avril 2017

derived from streambuf, ostream and manip - not compile or crashed

So, I started an indenting buffer/ostream,setting the indent level using manipulators and run into problems... The first was the compiler error indent_ostream& increase(indent_ostream&)' will always evaluate as 'true'. Just made a operator<< for function pointers as member of the ostream. The next than was ambiguous overload for 'operator<<' (operand types are 'indent_ostream' and 'int'). Also added a member operator<< with templated argument to catch all types to be streamed (string, int, etc).This results into an Segmentation fault and here I am :(

#include <iostream>
#include <streambuf>
#include <iomanip>

class indent_sbuf : public std::streambuf
{
    std::streambuf*     m_sbuf;
    std::string         m_indent_str;
    bool                m_start_of_line;
    static const int    TAB_WIDTH = 4;

public:
    explicit indent_sbuf(std::streambuf* sbuf, size_t indent = 0)
        : m_sbuf{ sbuf }
        , m_indent_str(indent, ' ')
        , m_start_of_line{ true }
    { }

    ~indent_sbuf()
    {
        overflow('\n');
    }

    indent_sbuf& increase()
    {
        m_indent_str = std::string(m_indent_str.size() + TAB_WIDTH, ' ');
        return *this;
    }

    indent_sbuf& decrease()
    {
        if(m_indent_str.size() > TAB_WIDTH) {
            m_indent_str = std::string(m_indent_str.size() - TAB_WIDTH, ' ');
        }
        else {
            m_indent_str = "";
        }
        return *this;
    }

private:
    int_type overflow(int_type chr) override
    {
        if (m_start_of_line && chr != '\n') {
            m_sbuf->sputn( m_indent_str.data(), m_indent_str.size() );
        }
        m_start_of_line = (chr == '\n');
        return m_sbuf->sputc( chr );
    }
};

class indent_ostream : public std::ostream
{
    indent_sbuf buf;

public:
    indent_ostream(std::ostream& os, size_t width)
        : std::ostream(&buf)
        , buf(os.rdbuf(), width)
    { }

    indent_ostream& operator<<(indent_ostream& (*fcn)(indent_ostream&))
    {
        return (*fcn)(*this);
    }

    template<typename T>
    indent_ostream& operator<<(T const& v) // get it to compile
    {
        *this << v; // but crash
        return *this;
    }
};

static inline
indent_ostream& increase(indent_ostream& os)
{
    indent_sbuf* buf = static_cast<indent_sbuf*>(os.rdbuf());
    buf->increase();
    return os;
}

static inline
indent_ostream& decrease(indent_ostream& os)
{
    indent_sbuf* buf = static_cast<indent_sbuf*>(os.rdbuf());
    buf->decrease();
    return os;
}


int main()
{
    indent_ostream os(std::cout, 0);
    os << "Hallo\n";
    os << increase << "World\n";
    os << decrease << 42 << "\n";
}

Also at coliru. So, what going on here and where are my faults? How to get it working correct and standard conforming?

Aucun commentaire:

Enregistrer un commentaire