File: defining.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 (106 lines) | stat: -rw-r--r-- 4,973 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
The arguments associated with a variadic template parameter are not directly
available to the implementation of a function or class template. We have to
resort to other means to obtain them.

By defining a partial specialization of a variadic template, explicitly
defining an additional template type parameter, we can associate the first
template argument of a parameter pack with this additional (first) type
parameter. The setup of such a variadic function template (e.g., tt(printcpp),
see the previous section) is as follows:
    itemization(
    it() The tt(printcpp) function receives at least a format
string. Following the format string any number of additional arguments may be
specified.
    it() If there are no arguments trailing the format string then there is no
need to use a function template. An overloaded (non-template) function
is defined to handle this situation.
    it() A variadic function template handles all remaining situations. In
this case there is always at least one  argument trailing the format
string. That argument's type is matched with the variadic template function's
first (ordinary) template type parameter tt(First). The types of any remaining
arguments are bound to the template function's second template parameter,
which is a parameter pack.
    it() The variadic function template processes the argument trailing the
format string. Then it recursively calls itself passing the format string and
the parameter pack to the recursive call
    it() If the recursive call merely receives the format string the
overloaded (non-template) function is called (cf. section
ref(FUNCTIONSELECTION)) ending the recursion. Otherwise the parameter pack's
first argument is matched with the recursive call's tt(First) parameter. As
this reduces the size of the recursive call's parameter pack the recursion
eventually stops.
    )

The overloaded non-template function prints the remainder of the format
string, em(en passant) checking for any left-over format specifications:
        verb(    void printcpp(string const &format)
    {
        size_t left = 0;
        size_t right = 0;

        while (true)
        {
            if ((right = format.find('%', right)) == string::npos)
                break;
            if (format.find("%%", right) != right)
                throw std::runtime_error(
                            "printcpp: missing arguments");
            ++right;
            cout << format.substr(left, right - left);
            left = ++right;
        }
        cout << format.substr(left);
    })

Here is the variadic function template's implementation:
        verb(    template<typename First, typename ...Params>
    void printcpp(std::string const &format, First value, Params ...params)
    {
        size_t left = 0;
        size_t right = 0;
        while (true)
        {
            if ((right = format.find('%', right)) == string::npos)      // 1
                throw std::runtime_error("printcpp: too many arguments");

            if (format.find("%%", right) != right)                      // 2
                break;

            ++right;
            cout << format.substr(left, right - left);
            left = ++right;
        }
        cout << format.substr(left, right - left) << value;
        printcpp(format.substr(right + 1), params...);
   })

itemization(
    it() At 1 the format string is searched for a parameter specification
tt(%). If none is found then the function is called with too many arguments
and it throws an exception;
    it() At 2 it verifies that it has not encountered tt(%%). If only a single
tt(%) has been seen the tt(while)-loop ends, the format string is inserted
into tt(cout) up to the tt(%) followed by tt(value), and the recursive call
receives the remaing part of the format string as well as the remaining
parameter pack;
    it() If tt(%%) was seen the format string is inserted up to the second
tt(%), which is ignored, and processing of the format string continues beyond
the tt(%%).
    )
    Make sure that the overloaded function is at least declared before the
compiler processes the function template's definition or it won't
call the overloaded function tt(printcpp) when compiling the function
template.

    Different from bf(C)'s tt(printf) function tt(printcpp) only recognizes
tt(%) and tt(%%) as format specifiers. The above implementation does not
recognize, e.g., field widths. Type specifiers like tt(%c) and tt(%x) are of
course not needed as tt(ostream)'s insertion operator is aware of the types of
the arguments that are inserted into the tt(ostream).  Extending the format
specifiers so that field widths etc. are recognized by this tt(printcpp)
implementation is left as an exercise to the reader. Here is an example
showing how tt(printcpp) can be called:
        verb(    printcpp("Hello % with %%main%% called with % args"
                                            " and a string showing %\n",
        "world", argc, "A String"s);)