Stream manipulators in C++

July 7, 2017 · 4 minutes to read · C++

In C++ language, output streams are a nice way to display information in console. There are some caveats we can talk about - like bufferization, statefulness - but it is not the goal of this article.

Streams have a cool feature to format output (and input) called manipulators. Some of them:

  • flush / endl
  • oct / dec / hex
  • boolalpha / noboolalpha
  • setw() / setfill()

An interesting question is: can we add our owns manipulators? Yes we can! And this is the purpose of this post.

Foreword

In this article, I use std::locale::facet which is a feature of localization library. Its primary goal is to help to format output according to a selected locale.

So facet is not intended to be used to create manipulators. But it is a fun (and useful) way to format data on standard streams.

In std, manipulators set parameters directly on streams throught methods. We had to find a way to save a status without change standard streams or inherit from them.

Design

Imagine we want to create a manipulator which reverse a boolean:

cout << boolrev << true << endl;
must display:
$ 0

We can decompose implementation into several parts:

  • Retain the status (reversed or not).
  • Detect when user wants to display a boolean (and only a boolean).
  • Output the reversed value in the stream.
  • And the most important thing: how to tell to cout to understand our new manipulator.

Implementation

First let’s implement the status storage. The method iword of std::ios_base is the key. This function takes an index in argument and returns a storage location for a long.

1
2
ostream& boolrev(ostream &os) { os.iword(get_index()) = 1; return os; }
ostream& noboolrev(ostream &os) { os.iword(get_index()) = 0; return os; }

The index has to be unique. ios_base provides also a method to get a valid and unused index: xalloc.

1
2
3
4
5
static int get_index()
{
    static int i = ios_base::xalloc();
    return i;
}

Now, we have to intercept the call when user wants to display a boolean. We create a structure which inherits from num_put. This class is a tool to format numeric values as strings.

We check status of the manipulator, and output a value in result. Thanks to inheritence, we can use base method class so formatting with other manipulators is kept.

1
2
3
4
5
6
7
8
9
struct my_num_put : num_put<char>
{
    iter_type do_put(iter_type s, ios_base& f, char_type fill, bool b) const
    {
        if (f.iword(get_index()) == 1)
            return num_put<char>::do_put(s, f, fill, !b);
        return num_put<char>::do_put(s, f, fill, b);
    }
};

So now, we just have to connect all this stuff on output stream and use it!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>

using namespace std;

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

ostream& boolrev(ostream &os) { os.iword(get_index()) = 1; return os; }
ostream& noboolrev(ostream &os) { os.iword(get_index()) = 0; return os; }

struct my_num_put : num_put<char>
{
    iter_type do_put(iter_type s, ios_base& f, char_type fill, bool b) const
    {
        if (f.iword(get_index()) == 1)
            return num_put<char>::do_put(s, f, fill, !b);
        return num_put<char>::do_put(s, f, fill, b);
    }
};

int main()
{
    cout.imbue(locale(locale(), new my_num_put));

    cout << boolrev;
    cout << true << " / " << false << endl;

    cout << boolalpha;
    cout << true << " / " << false << endl;

    cout << noboolrev;
    cout << noboolalpha;
    cout << true << " / " << false << endl;

    return 0;
}

Do not forget to add the 26th line. It is needed to add this manipulator to stream.

Futhermore

  • Add one (or more) parameter(s) - like in setw(int)
  • Do not use facet by subclassing std::ostream
  • Create an input manipulator

For more informations about manipulators in the std, I guide you towards these links: