File: alternate.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-- 3,768 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
Traditional  bf(C++) requires function templates to specify their return type
or to specify the return type as a template type parameter. Consider the
following function:
        verb(    int add(int lhs, int rhs)
    {
        return lhs + rhs;
    })

The above function may be converted to a function template:
        verb(    template <typename Lhs, typename Rhs>
    Lhs add(Lhs lhs, Rhs rhs)
    {
        return lhs + rhs;
    })

Unfortunately, when the function template is called as
        verb(    add(3, 3.4))

the intended return type is probably a tt(double) rather than an
tt(int). This can be solved by adding an additional template type parameter
specifying the return type but then  that type must explicitly be specified:
        verb(    add<double>(3, 3.4);)

Using ti(decltype) (cf. section ref(AUTO)) to define the return type won't
work as tt(lhs) and tt(rhs) aren't known to the compiler by the time
tt(decltype) is used. Thus the next attempt to get rid of the additional
template type parameter fails to compile:
        verb(    template <typename Lhs, typename Rhs>
    decltype(lhs + rhs) add(Lhs lhs, Rhs rhs)
    {
        return lhs + rhs;
    })

The tt(decltype)-based definition of a function's return type may become
fairly complex. This complexity can be reduced by using the 
 emi(late-specified return type) syntax that em(does) allow the use of
tt(decltype) to define a function's return type. It is primarily used with
function templates but it may also be used for ordinary (non-template)
functions:
        verb(    template <typename Lhs, typename Rhs>
    auto add(Lhs lhs, Rhs rhs) -> decltype(lhs + rhs)
    {
        return lhs + rhs;
    })

When this function is used in a statement like tt(cout << add(3, 3.4)) the
resulting value will be 6.4, which is most likely the intended result, rather
than 6. As an example how a late-specified return type may reduce the
complexity of a function's return type definition consider the following:
        verb(    template <typename T, typename U>
    decltype((*(T*)0)+(*(U*)0)) add(T t, U u);)

Kind of hard to read? A term like tt( (*(T*)0) ) defines 0, using a bf(C)
    cast, as a pointer to type tt(T) and then dereferences the pointer,
    producing a value of type tt(T) (even though that value itself doesn't
    exist as a variable). Likewise for the second term that's used in the
    tt(decltype) expression. The resulting type is thereupon used as tt(add's)
    return type. 
    Using a late-specified return type we get the equivalent:
        verb(    template <typename T, typename U>
    auto add(T t, U u) -> decltype(t+u);)

which most people consider easier to understand.

The expression specified with tt(decltype) does not necessarily use the
parameters tt(lhs) and tt(rhs) themselves. In the next function
definition tt(lhs.length) is used instead of tt(lhs) itself:
        verb(    template <typename Class, typename Rhs>
    auto  add(Class lhs, Rhs rhs) -> decltype(lhs.length() + rhs)
    {
        return lhs.length() + rhs;
    })

em(Any) variable visible at the time tt(decltype) is compiled can be used
in the tt(decltype) expression. It is also possible to
handle member selection through pointers to members. The following code aims
at specifying the address of a member function as tt(add)'s first argument and
then use its return value type to determine the function template's return
type. Here is an example:
        verb(    std::string global{"hello world"};

    template <typename MEMBER, typename RHS>
    auto  add(MEMBER mem, RHS rhs) -> decltype((global.*mem)() + rhs)
    {
        return (global.*mem)() + rhs;
    }

    int main()
    {
        std::cout << add(&std::string::length, 3.4) << '\n'; // shows: 14.4
    })