Tristan Havelick Tristan Havelick -4 years ago 234
C++ Question

C++ custom stream manipulator that changes next item on stream

In C++, to print a number in hexadecimal you do this:

int num = 10;
std::cout << std::hex << num; // => 'a'


I know I can create a manipulator that just adds stuff to the stream like so:

std::ostream& windows_feed(std::ostream& out)
{
out << "\r\n";
return out;
}

std::cout << "Hello" << windows_feed; // => "Hello\r\n"


However, how can I create a manipulator that, like 'hex', modifies items to come on the stream? As a simple example, how would I create the plusone manipulator here?:

int num2 = 1;
std::cout << "1 + 1 = " << plusone << num2; // => "1 + 1 = 2"

// note that the value stored in num2 does not change, just its display above.
std::cout << num2; // => "1"

Answer Source

First, you have to store some state into each stream. You can do that with the function iword and an index you pass to it, given by xalloc:

inline int geti() { 
    static int i = ios_base::xalloc();
    return i;
}

ostream& add_one(ostream& os) { os.iword(geti()) = 1; return os; } 
ostream& add_none(ostream& os) { os.iword(geti()) = 0; return os; }

Having that in place, you can already retrieve some state in all streams. Now, you just have to hook into the respective output operation. Numeric output is done by a facet, because it potentially is locale dependent. So you can do

struct my_num_put : num_put<char> {
    iter_type 
    do_put(iter_type s, ios_base& f, char_type fill, long v) const { 
        return num_put<char>::do_put(s, f, fill, v + f.iword(geti())); 
    } 

    iter_type 
    do_put(iter_type s, ios_base& f, char_type fill, unsigned long v) const { 
        return num_put<char>::do_put(s, f, fill, v + f.iword(geti())); 
    } 
}; 

Now, you can test the stuff.

int main() {
    // outputs: 11121011
    cout.imbue(locale(locale(),new my_num_put));
    cout << add_one << 10 << 11 
         << add_none << 10 << 11;
}

If you want that only the next number is incremented, just set the word to 0 again after each call to do_put.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download