File: parentheses.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 (58 lines) | stat: -rw-r--r-- 2,631 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
Let's play some more. At some point in our program we defined tt(int b). Then,
in a compound statement we need to construct an em(anonymous) tt(Data) object,
initialized by tt(b), and then we're supposed to display tt(b) itself:
    COMMENT(examples/ambiguity.cc)
            verb(    int b = 18;
    {
        Data(b);
        cout << b;
    })

About that tt(cout) statement the compiler tells us (I modified the
error message to reveal its meaning):

em(error: cannot bind `std::ostream & << Data const &')

Here we didn't insert tt(int b) but tt(Data b). Had we omitted the compound
statement, the compiler would have complained about a doubly defined tt(b)
entity, as tt(Data(b)) simply means tt(Data b), a tt(Data) object constructed
by default. Here, the parentheses around tt(b) are superfluous and may be
omitted by the compiler when parsing a definition or declaration.

    Of course, the question now becomes how a temporary object tt(Data),
initialized with tt(int b) em(can) be defined. Remember that the compiler may
remove superfluous parentheses. So, what we need to do is to pass an tt(int)
to the anonymous tt(Data) object, without using the tt(int)'s name.
    itemization(
    it() We can use a cast: tt(Data(static_cast<int>(b)));
    it() We can use a curly brace initialization: tt(Data{ b }).
    )

Values and types make big differences. Consider the following definitions:
        verb(    Data (*d4)(int);    // 1
    Data (*d5)(3);      // 2)

Definition 1 should cause no problems: it's a pointer to a function,
expecting an tt(int), returning a tt(Data) object. Hence, tt(d4) is a pointer
variable.  

    Definition 2 is slightly more complex. Yes, it's a pointer. But it has
nothing to do with a function. So what's that argument list containing 3 doing
there? Well, it's not an argument list. It's an initialization that looks like
an argument list. Remember: variables can be initialized using assignment
statements, using parentheses, or using curly braes. In general, they're
interchangeable. So instead of tt(`(3)') we could have written tt(`= 3') or
tt(`{3}'). Let's pick the first alternative, resulting in:
        verb(    Data (*d5) = 3;)

Now we get to `play compiler' again. Removing some more superfluous
parentheses we get:
        verb(    Data *d5 = 3;)

It's a pointer to a tt(Data) object, initialized to 3. This is
em(syntactically) correct, but em(semantically) incorrect: at address 3
there's no tt(Data) object. If we had initially written
        verb(     Data (*d5)(&d1);      // 2)

the fun resulting from contrasting tt(int) and tt(3) would most likely
have been masked.