源自streambuf,ostream和manip - 不编译或崩溃

时间:2017-04-26 17:23:13

标签: c++ c++11 c++14

所以,我启动了一个缩进缓冲区/ ostream,使用操纵器设置缩进级别并遇到问题......首先是编译错误 indent_ostream& increase(indent_ostream&)' will always evaluate as 'true'。刚做了一个算子&lt;&lt;将函数指针作为ostream的成员。下一个是ambiguous overload for 'operator<<' (operand types are 'indent_ostream' and 'int')。还添加了一个成员运算符&lt;&lt;使用模板化参数来捕获所有要流式传输的类型(字符串,整数等)。这导致Segmentation fault,我在这里:(

#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";
}

同样在coliru。那么,这里发生了什么,我的错在哪里?如何让它正常工作并符合标准?

1 个答案:

答案 0 :(得分:3)

所以你收到了警告:

  

第一个是编译器错误indent_ostream& increase(indent_ostream&)'将始终评估为'true'

为什么呢?那是什么意思? os << increase实际上做了什么?不要忽视警告!它指出你的代码中存在真正的问题!究!

如果你查看operator<<的运算符列表,就会出现这个:

basic_ostream& operator<<(
    std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );

但是那个与你的功能不匹配,它不是一个可行的候选人。函数Derived&(*)(Derived&)Base&(*)(Base&)不匹配 - 它永远不会有效。相反,最好(唯一)可行的候选人是:

basic_ostream& operator<<( bool value );

因为函数指针可以转换为bool。警告是这很愚蠢,因为很明显这会打印1,可能不是你打算做的。

但实际上 该函数无论如何都不需要indent_ostream。你关心的只是缓冲区。所以解决方案是修复你的修饰符以匹配预期的签名:

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

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

现在,它有效!