File: specialization.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 (92 lines) | stat: -rw-r--r-- 4,724 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
    The initial tt(add) template, defining two identically typed parameters
works fine for all types supporting tt(operator+) and a copy
constructor. However, these assumptions are not always met. For example, with
tt(char *)s, using tt(operator+) or a `copy constructor' does not make
sense. The compiler tries to instantiate the function template, but
compilation fails as  tt(operator+) is not defined for pointers.

In such situations the compiler may be able to resolve the template type
parameters but it (or we ...) may then detect that the standard implementation
is pointless or produces errors.

    To solve this problem a emi(template explicit specialization) may be
defined.  A template explicit specialization defines the function template for
which a generic definition already exists using specific actual template type
parameters. As we saw in the previous section the compiler always prefers
a more specialized function over a less specialized one. So the template
explicit specialization is selected whenever possible.

A template explicit specialization offers a specialization for its template
type parameter(s). The special type is consistently substituted for
the template type parameter in the function template's code. For
example if the explicitly specialized type is tt(char const *) then in the
template definition
        verb(    template <typename Type>
    Type add(Type const &lhs, Type const &rhs)
    {
        return lhs + rhs;
    })

tt(Type) must be replaced by tt(char const *), resulting in a function
having prototype
        verb(    char const *add(char const *const &lhs, char const *const &rhs);)

Now we try to use this function:
        verb(    int main(int argc, char **argv)
    {
        add(argv[0], argv[1]);
    })

However, the compiler ignores our specialization and tries to instantiate
the initial function template. This fails, leaving us wondering why it didn't
select the explicit specialization....

    To see what happened here we replay, step by step, the compiler's actions:
    itemization(
    it() tt(add) is called with tt(char *) arguments.
    it() Both types are equal, so the compiler deduces that tt(Type) equals
tt(char *).
    it() Now it inspects the specialization. Can a tt(char *) template type
argument match a tt(char const *const &) template parameter? Here
opportunities for the allowable transformations from section ref(TEMPFUNARGS)
may arise. A qualification transformation seems to be the only viable one,
allowing the compiler to bind a const-parameter to a non-const argument.
    it() So, in terms of tt(Type) the compiler can match an argument of some
tt(Type) or an argument of some tt(Type const) to a tt(Type const &).
    it() tt(Type) itself is not modified, and so tt(Type) is a tt(char *).
    it() Next the compiler inspects the available explicit specializations. It
finds one, specializing for tt(char const *).
    it() Since a tt(char const *) is not a tt(char *) it rejects the explicit
specialization and uses the generic form, resulting in a compilation error.
    )
    If our tt(add) function template should also be able to handle tt(char *)
template type arguments another explicit specialization for tt(char *) may be
required, resulting in the prototype
        verb(    char *add(char *const &lhs, char *const &rhs);)

Instead of defining another explicit specialization an em(overloaded)
function template could be designed expecting pointers. The following function
template definition expects two pointers to constant tt(Type) values and
returns a pointer to a non-constant tt(Type):
        verb(    template <typename Type>
    Type *add(Type const *t1, Type const *t2)
    {
        std::cout << "Pointers\n";
        return new Type;
    })

What actual types may be bound to the above function parameters? In this
case only a tt(Type const *), allowing tt(char const *)'s to be passed as
arguments. There's no opportunity for a qualification transformation here.
The qualification transformation allows the compiler to add a tt(const) to a
non-const argument if the parameter itself (and em(not)  tt(Type)) is
specified in terms of a tt(const) or tt(const &). Looking at, e.g., tt(t1) we
see that it's defined as a tt(Type const *). There's nothing tt(const) here
that's referring to the parameter (in which case it would have been tt(Type
const *const t1) or tt(Type const *const &t1)). Consequently a qualification
transformation cannot be applied here.

    As the above overloaded function template only accepts tt(char const *)
arguments, it will not accept (without a reinterpret cast) tt(char *)
arguments. So tt(main)'s tt(argv) elements cannot be passed to our overloaded
function template.