File: simple.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 (133 lines) | stat: -rw-r--r-- 6,064 bytes parent folder | download | duplicates (2)
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
Here are some examples of how simple definitions where the compiler deduces
template arguments can (and cannot) be specified. 

    Starting point:
    verb(    template <class ...Types>           // any set of types
    class Deduce
    {
        public:
            Deduce(Types ...params);    // constructors
            void fun();                 // a member function
    };)

Some definitions:
        verb(                                    // deduce:     full definition:
                                    // --------------------------------
    Deduce first{1};                // 1: int   -> Deduce<int> first{1} 
    Deduce second;                  // no Types -> Deduce<> second;  
    Deduce &&ref = Deduce<int>{ 1 };// int      -> Deduce<int> &&ref

    template <class Type>
    Deduce third{ static_cast<Type *>(0) };)

The template tt(third) is a recipe for constructing tt(Deduce)
objects from a type that's specified for tt(third). The pointer's type simply 
is a pointer to the specified type (so, specifying tt(third<int>) implies an
tt(int *)). Now that the type of tt(third)'s argument is available (i.e., an
tt(int *)) the compiler deduces that tt(third{0}) is a tt(Deduce<int *>).

This tt(Deduce<int *>) object could, e.g., be used to initialize a named
tt(Deduce<int *>) object:
        verb(    auto x = third<int>;        // x's full definition: Deduce<int *> x{0})

tt(Deduce's) member functions can be used by anonymous and named objects:
        verb(    x.fun();                    // OK: fun called by named object
    third<int>.fun();           // OK: fun called by anonymous object)

Here are some examples that won't compile:
        verb(    extern Deduce object;       // not an object definition
    Deduce *pointer = 0;        // any set of types could be intended
    Deduce function();          // same.)

When defining objects, either using function-type or curly brace definitions
template argument deduction is realized as follows:
    itemization(
    it() First, a list of available constructors is formed. The list contains
all available ordinary constructors and constructor templates (i.e,
constructors defined as member templates);
    it() For each element of that list a parallel imaginary function
is formed by the compiler (forming function templates for constructor
templates, and ordinary functions for ordinary constructors);
    it() The return types of these imaginary functions are the class types of
the constructors, using the template parameters of the original class
template. For example, for the tt(Deduce::Deduce) constructor the imaginary
function 
        verb(    template <class ...Types>
    Deduce<Types ...> imaginary(Types ...params);)

is formed.
    it() Next, ordinary argument deduction and overload resolution is applied
to the set of imaginary functions. If this results in a best match for 
one of these imaginary functions then that function's class type (or
specialization) will be used. Otherwise the program is ill-formed.
    )

Let's apply this process to the class tt(Deduce). The set of imaginary
functions matching tt(Deduce) looks like this:
        verb(                                        // already encountered: matching
    template <class ...Types>           // Deduce(Types ...params)
    Deduce<Types ...> imaginary(Types ...params);

                                        // the copy constructor: matching
    template <class ...Types>           // Deduce(Deduce<Types ...> const &)
    Deduce<Types ...> imaginary(Deduce<Types ...> const &other);
                                    
                                        // the move constructor, matching
    template <class ...Types>           // Deduce(Deduce<Types ...> &&)
    Deduce<Types ...> imaginary(Deduce<Types ...> &&tmp);)

For the construction tt(Deduce first{1}) the first imaginary function wins
the overload contest, resulting in the template argument deduction tt(int) for
tt(class ...Types), and hence tt(Deduce<int> first{1}) is defined.

Note that when a class template is nested under a class template, the nested
class template's name depends on the outer class type. The outer class then
provides the name qualifier for the inner class template. In such cases
template argument deduction is used for the nested class, but (as it is not
used for name qualifiers) is not used for the outer class. Here is an example:
adding a nested class template to tt(Outer):

    verb(    template <class OuterType>
    class Outer
    {
        public:
            template <class InnerType>
            struct Inner
            {
                Inner(OuterType);
                Inner(OuterType, InnerType);
                template <typename ExtraType>
                Inner(ExtraType, InnerType);
            };
    };
    // defining:
    Outer<int>::Inner inner{2.0, 1};)

In this case, the compiler uses these imaginary functions:
    verb(    template <typename InnerType>
    Outer<int>::Inner<InnerType>            // copy constructor
        imaginary(Outer<int>::Inner<InnerType> const &);

    template <typename InnerType>       
    Outer<int>::Inner<InnerType>            // move constructor
        imaginary(Outer<int>::Inner<InnerType> &&);

    template <typename InnerType>           // first declared constructor
    Outer<int>::Inner<InnerType> imaginary(int);

    template <typename InnerType>           // second declared constructor
    Outer<int>::Inner<InnerType> imaginary(int, InnerType);

    template <typename InnerType>           // third declared constructor
    template <typename ExtraType>       
    Outer<int>::Inner<InnerType> imaginary(ExtraType, InnerType);)

Template argument deduction for calling  tt(imaginary(2.0, 1)) results in
tt(double) for its first argument and tt(int) for its second. Overload
resolution then favors the last imaginary function, and so tt(ExtraType:
double) and tt(InnerType: int). Consequently, 
    verb(    Outer<int>::Inner inner{ 2.0, 1 };)

is defined as:
    verb(    Outer<int>::Inner<int> Inner{ 2.0, 1 };)