creating an ostream
Asked Answered
S

4

7

I am trying to create a c++ ostream for educational reasons. My test will be creating an ostream that acts like a ofstream would except instead of writing to a file it would write to a deque or vector container.

Sleeve answered 7/2, 2009 at 20:32 Comment(1)
Perhaps you could improve your question to ask an actual question.Caudle
G
14

As it is for education, as you say, i will show you how i would do such a thingy. Otherwise, stringstream is really the way to go.

Sounds like you want to create a streambuf implementation that then writes to a vector / deque. Something like this (copying from another answer of me that targeted a /dev/null stream):

template<typename Ch, typename Traits = std::char_traits<Ch>,
         typename Sequence = std::vector<Ch> >
struct basic_seqbuf : std::basic_streambuf<Ch, Traits> {
     typedef std::basic_streambuf<Ch, Traits> base_type;
     typedef typename base_type::int_type int_type;
     typedef typename base_type::traits_type traits_type;

     virtual int_type overflow(int_type ch) {
         if(traits_type::eq_int_type(ch, traits_type::eof()))
             return traits_type::eof();
         c.push_back(traits_type::to_char_type(ch));
         return ch;
     }

    Sequence const& get_sequence() const {
        return c;
    }
protected:
    Sequence c;
};

// convenient typedefs
typedef basic_seqbuf<char> seqbuf;
typedef basic_seqbuf<wchar_t> wseqbuf;

You can use it like this:

seqbuf s;
std::ostream os(&s);
os << "hello, i'm " << 22 << " years old" << std::endl;
std::vector<char> v = s.get_sequence();

If you want to have a deque as sequence, you can do so:

typedef basic_seqbuf< char, char_traits<char>, std::deque<char> > dseq_buf;

Or something similar... Well i haven't tested it. But maybe that's also a good thing - so if it contains still bugs, you can try fixing them.

Guillermoguilloche answered 7/2, 2009 at 21:9 Comment(1)
Thanks for code snippet. While the same approach used here #760801 to disable output, I wonder if it is optimal to do per-character processing (as overflow takes one char at a time) or is there any way to intersect basic_streambuf::sputn(const char* s, streamsize n)?Counterinsurgency
R
4

Use std::stringstream

#include <iostream>
#include <sstream>
int main()
{
    std::stringstream   s;
    s << "Plop" << 5;

    std::cout << s.str();
}
Randolphrandom answered 7/2, 2009 at 20:42 Comment(2)
That writes a string though, while it might be intended to write the "5" as a binary integer.Cassey
@JeroenBollen: Much easier to use what already exists to do that: https://mcmap.net/q/1476018/-converting-to-binary-in-c . std::cout << std::bitset<4>(5) << "\n";Randolphrandom
F
2

I'll just remark that you don't have to write an ostream-like class for that. You can use an adapter to achieve your goal.

For example, this code reads from istream and inserts each element into a vector:

vector<string> V;
copy(istream_iterator<string>(cin), 
     istream_iterator<string>(), 
     back_inserter(V)); 
Freewheel answered 7/2, 2009 at 21:6 Comment(0)
S
1

Without more detail on what you want to do it is hard to be too specific, but you don't want to create a new ostream. What you want to do is create a new type streambuf, and use an existing ostream.

The easyist thing to do is to inherit from std::basic_filebuf<>, and overload the sync() and overflow() methods to add elements to your data structures.

Seasonseasonable answered 7/2, 2009 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.