How to add indention to the stream operator

前端 未结 4 1224
予麋鹿
予麋鹿 2020-12-31 05:02

In our project we use the c++ stream operator (<<) in our object model to print out an easy readible format of the data. A simplified example is this:

         


        
4条回答
  •  囚心锁ツ
    2020-12-31 05:21

    This can be done using a custom stream-manipulator that stores the desired indentation-level in a word of the internal extensible array of the stream. You can request such a word using the function ios_base::xalloc. This function will give you the index of your word. You can access it using ios_base::iword. One way to implement that would be this:

    struct indent {
        indent(int level) : level(level) {}
    private:
        friend std::ostream& operator<<(std::ostream& stream, const indent& val);
    
        int level;
    };
    
    std::ostream& operator<<(std::ostream& stream, const indent& val) {
        for(int i = 0; i < val.level; i++) {
            stream << " ";
        }
        return stream;
    }
    
    std::ostream& operator<<(std::ostream & oStream, const OwnClass& iOwnClass) {
        oStream << indent(oStream.iword(index)) << "[SomeMember1: " << 
                   iOwnClass._ownMember1 << "]\n";
        oStream << indent(oStream.iword(index)) << "[SomeMember2: " << 
                   iOwnClass._ownMember2 << "]\n";
    }
    

    You'd have to figure out where to store the index. This effectively allows you to add custom state to the stream (note that this would not be thread-safe out-of-the-box). Every function that wants indentation should add the requested indentation to the stream, and subtract it again when it is done. You could make sure this always happen by using a guard to add/subtract the desired indent (IMHO this is more elegant than using a manipulator):

    class indent_guard {
    public:
        indent_guard(int level, std::ostream& stream, int index) 
        : level(level),
          stream(stream),
          index(index)
        {
            stream.iword(index) += level;
        }
    
        ~indent_guard() {
            stream.iword(index) -= level;
        }
    
     private:
         int level;
         std::ostream& stream;
         int index;
    };
    

    You could use it like this:

    void some_func() {
        indent_guard(2, std::cout, index);
    
        // all output inside this function will be indented by 2 spaces
    
        some_func(); // recursive call - output will be indented by 4 spaces
    
        // here it will be 2 spaces again
    }
    

提交回复
热议问题