The way to implement this logic is to create a custom stream buffer which writes at the opportune location in its overflow() method and then to create a suitable std::ostream using this stream buffer. Here is a rough sketch on how that would look like:
class posbuf: public std::streambuf {
    int d_row;     // current row
    int d_column;  // column where to start output
    void move() { /* use curses, VT100 codes, whatever to move the cursor */ }
    int overflow(int c) {
        if (c == traits_type::eof()) { return traits_type::not_eof(c); }
        if (c == '\n') { ++this->d_row; this->move(); return '\n'; }
        return std::cout << traits_type::to_char_type(c)? c: traits_type::eof();
    }
    int sync() {
        return std::cout.flush()? 0: -1;
    }
public:
    posbuf(int row, int column): d_row(row), d_column(column) { this->move(); }
};
struct oposstream: private virtual posbuf, public std::ostream {
    oposstream(int row, int column): posbuf(row,c column), std::ostream(this) {}
};
int main() {
    oposstream out(4, 10);
    out << "hello\nworld";
}
Except for a couple of likely typos and the details on how to actually move the cursor, the above code should actually work and create an std::ostream which can be passed wherever an std::ostream& is expected. Any attempt to overload the output operator using some templates will not work as well.