Reputation: 131920
Suppose I have a vector of chars (or just an iterator pair) which I want to print to an ostream. Now, I don't just want it printed - I want it to have specific kinds of spacing, I want a different representation of char values than just blurting them out to the terminal (say, both the char if it's printable and the escaped 2-digit or hex code.
Now I don't want to write my own custom code beyond the bare minimum - i.e. just a bit of glue and
void foo(ostream& os, char c) {
os << c << ' ' << as_hex(c);
}
(which is like a custom overload for operator<< without the return.)
I do not want to have to loop over the vecotr, and for each character to manually call the abve I want it to behave and look as though I'm just pipe my vector to my outoput stream, after having temporarily changed the latter's attributes. But occasionally I want the stream to go back to behaving normally, even for the same vector.
Can this be done reasonably/idiomatically?
Upvotes: 2
Views: 268
Reputation: 76336
For the overloading to be temporary, I thought it would be nice to do some stuff like in iomanip
. This will allow to do stuff like
int main()
{
std::vector<char> v{'a', 'b'};
/* v should be printed using foo_vector_print, perhaps
* next invocation should use a different format. */
std::cout << foo_vector_print() << v << std::endl;
}
The idea is to have something of the form:
stream << manip << vector;
where
stream << manip
will return an object of a class storing a reference to the stream.... << vector
will print using a specific format, then return a reference to the original stream.The following program shows how to do this:
#include <iostream>
#include <vector>
namespace detail
{
// A dummy class in detail namespace, simply records the original ostream object.
struct foo_vector_printer_imp
{
std::ostream *m_os;
};
};
// This particular implementation simply prints out the vectors size.
std::ostream &operator<<(detail::foo_vector_printer_imp imp, const std::vector<char> &v)
{
*imp.m_os << v.size();
return *imp.m_os;
}
struct foo_vector_print{};
/* The result of piping a foo_vector_print into an ostream,
* is a foo_vector_printer_imp object recording the ostream */
detail::foo_vector_printer_imp operator<<(std::ostream &os, const foo_vector_print &)
{
detail::foo_vector_printer_imp imp;
imp.m_os = &os;
return imp;
}
int main()
{
std::vector<char> v{'a', 'b'};
std::cout << foo_vector_print() << v << std::endl;
}
Upvotes: 1
Reputation: 8785
I assume that you know about operator overloading and your main problem is to how tell operator which formatting option to use, i.e. how to store arbitrary information in stream.
Anything derived from std::ios_base
(all standard stream classes) has .iword()
method which returns reference to long
from some internal storage and .pword()
, which returns reference to void*
. Unique index for these calls can be aquired through call to std::ios_base::xalloc()
Example of using stream storage to change behaviour of output operation:
#include <iostream>
#include <vector>
const int vprint_index = std::ios_base::xalloc();
std::ostream& operator<<(std::ostream& out, std::vector<char> vec)
{
if (out.iword(vprint_index) == 0) {
for(char c: vec)
out << c;
return out;
}
out.iword(vprint_index) = 0;
out << '{';
bool first = true;
for(char c: vec) {
if(!first)
out << ", ";
first = false;
out << c;
}
return out << '}';
}
int main()
{
std::vector<char> vector {'f', 'o', 'o'};
std::cout << vector << '\n';
std::cout.iword(vprint_index) = 1;
std::cout << vector << '\n';
std::cout << vector << '\n';
}
foo
{f, o, o}
foo
Upvotes: 2
Reputation: 118425
Well, you do have to write your custom code somewhere. The contents of your vector aren't going to write to a std::ostream
all by themselves.
You're really asking, from the looks of it, how to be able to use the <<
operator to operate on a std::vector<char>
. The following example should get you started:
#include <iostream>
#include <vector>
std::ostream &operator<<(std::ostream &o, const std::vector<char> &v)
{
// Fill in the blanks here.
return o;
}
// Example:
int main()
{
std::vector<char> v;
std::cout << v;
return 0;
}
Upvotes: 0