File: userdefined.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 (140 lines) | stat: -rw-r--r-- 5,193 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
In addition to the literal operators discussed in section ref(UDLITERALS) 
bf(C++) also offers a function template literal operator, matching the
prototype
        verb(    template <char ...Chars>
    Type operator "" _identifier())

This variadic non-type parameter function template defines no parameters,
but merely a variadic non-type parameter list.

    Its argument must be an int constant, as is also expected by the literal
operator defining an tt(unsigned long long int) parameter. All the characters
of the int constant are passed as individual tt(char) non-type template
arguments to the literal operator.

    For example, if tt(_NM2km) is a literal operator function template, it can
be called as tt(80_NM2km). The function template is then actually called as
tt(_NM2km<'8', '0'>()). If this function template merely uses template meta
programming techniques and only processes integral data then its actions can
be performed completely at compile-time. To illustrate this, let's assume
tt(NM2km) only processes and returns unsigned values.

The function template tt(_NM2km) can forward its argument to a class template,
defining an enum constant tt(value), and that performs the required
computations. Here is the implementation of the variadic literal operator
function template tt(_NM2km):
            verb(    template <char ... Chars>
    size_t constexpr operator "" _NM2km()
    {
        return static_cast<size_t>(             // forward Chars to NM2km
                NM2km<0, Chars ...>::value * 1.852);
    })

The class template tt(NM2km) defines three non-type parameters: tt(acc)
accumulates the value, tt(c) is the first character of the variadic non-type
parameters, while tt(...Chars) represents the remaining non-type parameters,
contained in a non-type parameter pack. Since tt(c) is, at each recursive
call, the next character from the original non-type parameter pack, the value
so far multiplied by 10 plus the value of the next character is passed as the
next accumulated value to its recursive call, together with the remaining
elements of the parameter pack, represented by tt(Chars ...):
            verb(    template <size_t acc, char c, char  ...Chars>
    struct NM2km
    {
        enum
        {
            value = NM2km<10 * acc + c - '0', Chars ...>::value
        };
    };)

Eventually, the parameter pack is empty. For this case a partial
specialization of tt(NM2km) is available:
        verb(    template <size_t acc, char c>   // empty parameter pack
    struct NM2km<acc, c>
    {
        enum
        {
            value = 10 * acc + c - '0'
        };
    };)

This works fine, but of course not in cases where binary, octal, or
hexadecimal values must also be interpreted. In that case we must first
determine whether the first character(s) indicate a special number
system. This can be determined by the class template tt(NM2kmBase), that is
now called from the tt(_NM2km) literal operator:
            verb(    template <char ... Chars>
    size_t constexpr operator "" _NM2km()
    {
        return static_cast<size_t>(         // forward Chars to NM2kmBase
                NM2kmBase<Chars ...>::value * 1.852);
    })

The tt(NM2kmBase) class template normally assumes the decimal number
system, passing base value 10 and initial sum 0 to tt(NM2km). The tt(NM2km)
class template is provided with an additional (first) non-type parameter
representing the base value of the number system to use. Here is
tt(NM2kmBase):
        verb(    template <char ...Chars>
    struct NM2kmBase
    {
        enum
        {
            value = NM2km<10, 0, Chars ...>::value
        };
    };)

Partial specializations handle the different number systems, by inspecting
the first (one or two) characters:
        verb(    template <char ...Chars>
    struct NM2kmBase<'0', Chars ...>        // "0..."
    {
        enum
        {                                   // octal value: base 8
            value = NM2km<8, 0, Chars ...>::value
        };
    };

    template <char ...Chars>
    struct NM2kmBase<'0', 'b', Chars ...>   // "0b..."
    {
        enum
        {                                   // binary value: base 2
            value = NM2km<2, 0, Chars ...>::value
        };
    };

    template <char  ...Chars>
    struct NM2kmBase<'0', 'x', Chars ...>   // "0x..."
    {
        enum
        {                                   // hex value: base 16
            value = NM2km<16, 0, Chars ...>::value
        };
    };)

tt(NM2km) is implemented as before, albeit that it can now handle
various number systems. The conversion from character to numeric value is left
to a small support function template, tt(cVal):
        verb(    template <char c>
    int constexpr cVal()
    {
        return '0' <= c <= '9' ? c - '0' : 10 + c - 'a';
    }

    template <size_t base, size_t acc, char c, char  ...Chars>
    struct NM2km
    {
        enum
        {
            value = NM2km<base, base * acc + cVal<c>(),
                                        Chars ...>::value
        };
    };

    template <size_t base, size_t acc, char c>
    struct NM2km<base, acc, c>
    {
        enum { value = base * acc + cVal<c>() };
    };)