views:

1048

answers:

7

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"
A: 

The hex, dec and oct manipulators simply change the basefield property of the existing stream.

See C++ Reference for more deatail about these manipulators.

As posted in Neil Butterworth's answer, you would need to extend the existing stream classes, or create your own, in order to have manipulators that affect future values inserted into the stream.

In the example of your plusone manipulator, the stream object would have to have an internal flag to indicate that one should be added to all inserted values. The plusone manipulator would simply set that flag, and the code to handle stream insertion would check that flag before inserting numbers.

e.James
Have to -1 sorry -- iostreams do contain an extensibility mechanism (xalloc(), iword(), pword()) as pointed out by litb.
j_random_hacker
No need to apologize. I was clearly wrong, and I wouldn't have known without seeing the -1. Thank you for bringing it to my attention!
e.James
+4  A: 

I totally agree with Neil Butterworth on this one, however in the specific case you are using you could do this totally horrible hack. Do not do this in any production code. It has lots of bugs. For one thing it only works in your one-liner above, it does not change the state of the underlying stream.

class plusone_stream : public std::ostream
{
  public:
    std::ostream operator<<(int i)
    {
      _out << i+1;
      return *this;
    }
};

std::ostream& plusone(std::ostream& out)
{
    return plusone_stream(out);
}
1800 INFORMATION
You beat me to it :)
Benoît
+1  A: 

I created a simple solution for your test case without using <iomanip>. I can't promise that the same approach will work in real life.

The basic approach is that cout << plusone returns a temporary auxiliary object (PlusOnePlus), which in turn has the overloaded operator << that performs the addition.

I've tested it on Windows:

PlusOne plusone;
cout << plusone << 41

produces "42", as expected. Here's the code:

class PlusOnePlus {
public:
    PlusOnePlus(ostream& os) : m_os(os) {}
    // NOTE: This implementation relies on the default copy ctor,
    // assignment, etc.
private:
    friend ostream& operator << (PlusOnePlus& p, int n);
    ostream& m_os;
};

class PlusOne {
public:
    static void test(ostream& os);
};

PlusOnePlus operator << (ostream& os, const PlusOne p)
{
    return PlusOnePlus(os);
}

ostream& operator << (PlusOnePlus& p, int n)
{
    return p.m_os << n + 1;
}

void PlusOne::test(ostream& os)
{
    PlusOne plusone;
    os << plusone << 0 << endl;
    os << plusone << 41 << endl;
}

EDIT: Commented the code to point out that I'm relying on the default copy constructor (etc.) for PlusOnePlus. A robust implementation would probably define these

Dan Breslau
Clever, but note that the following will not work: "os << plusone; os << 41;"
j_random_hacker
I could argue that that's a feature :-) though admittedly it's inconsistent with the standard way that manipulators operate.
Dan Breslau
Yeah, I doubt anyone will notice one more more gratuitous inconsistency in C++... ;) +1.
j_random_hacker
+13  A: 

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.

Johannes Schaub - litb
You know that scene in Wayne's World where Wayne and Garth meet up with Alice Cooper? Yeah that's me right now
1800 INFORMATION
+1. This is the thorough, by-the-book (and as you can see, fairly complex) solution. But I wonder if it would not be simpler (and possibly clearer) to just create a function plusone() that takes one argument and returns the result?
j_random_hacker
very nice exposition!
anon
Thanks folks :)
Johannes Schaub - litb
A: 

You'll have to play with streamstates. I've bookmarked the following links on the subject:

Luc Hermitte
A: 

litb's approach is "the right way" and necessary for complicated stuff, but something like this can be good enough. Add privacy and friendship to taste.

struct PlusOne
{
   PlusOne(int i) : i_(i) { }
   int i_;
};

std::ostream &
operator<<(std::ostream &o, const PlusOne &po)
{
   return o << (po.i_ + 1);
}

std::cout << "1 + 1 = " << PlusOne(num2); // => "1 + 1 = 2"

In this simple example creating and streaming a temporary object doesn't seem much more helpful than defining a function plusOne() as someone already suggested. But suppose you wanted it to work like this:

std::ostream &
operator<<(std::ostream &o, const PlusOne &po)
{
   return o << po.i_ << " + 1 = " << (po.i_ + 1);
}

std::cout << PlusOne(num2); // => "1 + 1 = 2"
Dan
A: 

It's not a direct answer to your question, but don't you think that using a plain old function is both simpler to implement and clearer to use than writing a full blown manipulator?

#include <sstream>

template<typename T>
std::string plusone(T const& t) {
    std::ostringstream oss;
    oss << (t + 1);
    return oss.str();
}

Usage:

cout << plusone(42);

By "clear to use", I mean that the user doesn't need to ask themselves, "Does it affect only the next item, or all subsequent items?" It's obvious from inspection that only the argument of the function is affected.

(For the plusone() example, you could simplify even further by just returning a T instead, but returning a std::string serves the general case.)

j_random_hacker