File: argmanipulators.yo

package info (click to toggle)
c%2B%2B-annotations 13.02.02-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,576 kB
  • sloc: cpp: 25,297; makefile: 1,523; ansic: 165; sh: 126; perl: 90; fortran: 27
file content (82 lines) | stat: -rw-r--r-- 3,875 bytes parent folder | download | duplicates (4)
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
Manipulators taking arguments are implemented as hi(macro) macros: they are
handled by the i(preprocessor), and are not available beyond the preprocessing
stage.  

Manipulators, maybe requiring arguments, can also be defined without using
macros. One solution, suitable for modifying globally available objects (like
tt(cin), or tt(cout)) is based on using hi(anonymous object) anonymous
objects:
    itemization(
    it() First, a class is defined, e.g. tt(Align), whose i(constructor)
expects the arguments configuring the required manipulation. In our example
representing, respectively, a field width and an alignment type.
    it() The class also supports an overloaded insertion (or extraction)
operator. E.g.,
        verb(    ostream &operator<<(ostream &ostr, Align const &align))

it() Next, the (anonymous) object is inserted into a stream. The insertion
operator passes the stream to tt(Align::align), allowing that member to
configure (and return) the provided stream.
    )
    Here is an example of a little program using such a em(home-made)
manipulator expecting multiple arguments:
        verbinclude(-a examples/manipulator.cc)

When (local) objects must be manipulated, then the class that must provide
manipulators may define function call operators receiving the required
arguments. E.g., consider a class tt(Matrix) that should allow its users to
specify the value and line separators when inserting the matrix into an
tt(ostream). 

Two data members (e.g., tt(char const *d_valueSep) and tt(char const
*d_lineSep)) are defined (and initialized to acceptable values). The
insertion function inserts tt(d_valueSep) between values, and tt(d_lineSep) at
the end of inserted rows. The member tt(operator()(char const *valueSep, char
const *lineSep)) simply assigns values to the corresponding data members.

Given an object tt(Matrix matrix), then at this point tt(matrix(" ", "\n"))
can be called. The function call operator should probably not insert the
matrix, as the responsibility of manipulators is to manipulate, not to
insert. So, to insert a matrix a statement like 
    verb(        cout << matrix(" ", "\n") << matrix << '\n';)

should probably be used. The manipulator (i.e., function call operator)
assigns the proper values to tt(d_valueSep) and tt(d_lineSep), which are then
used during the actual insertion.

The return value of the function call operator remains to be specified. The
return value should be insertable, but in fact should not insert anything at
all. An empty NTBS could be returned, but that's a bit kludge-like. Instead
the address of a manipulator function, not performing any action, can be
returned. Here's the implementation of such an empty manipulator:
    verb(        // static       (alternatively a free function could be used)
        std::ostream &Matrix::nop(std::ostream &out)
        {
            return out;
        })

Thus, the implementation of the tt(Matrix's) manipulator becomes:
    verb(        std::ostream &( 
            *Matrix::operator()(char const *valueSep, char const *lineSep) ) 
                                                            (std::ostream &)
        {
            d_valueSep = valueSep;
            d_lineSep = lineSep;
            return nop;
        })

Instead (probably a matter of taste) of returning the address of an empty
function the manipulator could first set the required insertion-specific
values and could then return itself: the tt(Matrix) would be inserted
according to the just assigned values to the insertion variables:
    verb(        Matrix const &Matrix::operator()
            (char const *valueSep, char const *lineSep)
        {
            d_valueSep = valueSep;
            d_lineSep = lineSep;
            return *this;
        })

In this case the insertion statement is simplified to
        verb(    cout << matrix(" ", "\n") << '\n';)