

How to interpret complex C/C++ declarations (2004) - prajjwal
http://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations

======
Sharlin
The main things to remember is that declaration mirrors use, and you don't
actually directly declare the type of the variable, you declare the type of
the expression that the declaration mirrors.

    
    
      // x has type int
      int x;
    
      // the expression *x has type int
      // -> x is something that, when dereferenced, yields an int 
      // -> x is a pointer to int
      int *x;
    
      // x[n] has type int for some integer n 
      // -> x is something, when applied the array subscript operator to, yields an int
      // -> x is an array of ints
      int x[5];
    
      // x() has type int 
      // -> x is something that, when called, returns int
      // -> x is a function returning int
      int x();
    
      // *x() has type int 
      // -> by operator precedence, calling x, then applying *, yields an int
      // -> x is a function returning a pointer to int
      int *x();
    
      // (*x)() has type int
      // -> dereferencing x, then calling the result, yields an int
      // -> x is a pointer to a function returning int.
      int (*x)();

~~~
ygra
I've never noticed this before. Honestly, this makes things _a lot_ clearer.
And while it's still not terribly easy to figure out things like char ( _(_
x())[5])() it makes a lot more sense.

------
terhechte
I find complex Scala declarations much harder to parse. Have a look at these
examples:

def scanLeft[B, That](z: B)(op: (B, A) ⇒ B)(implicit bf:
CanBuildFrom[Iterable[A], B, That]): That

implicit def flatten5[A, B, C, D, E, F](f: (A, B, C, D, E) ⇒ F):
((ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[(ImplicitConversions.this)#~[A,
B], C], D], E]) ⇒ F

implicit def flatten5[A, B, C, D, E, F](f: (A, B, C, D, E) ⇒ F): (~[~[~[~[A,
B], C], D], E]) ⇒ F

These are, thankfully, exceptions and most declarations are easier to read,
nevertheless, as a Scala beginner, it takes me quite some time parsing such a
declaration when I intend to utilize the function in question. But that's
probably the price to pay for complex static typing.

~~~
bjz_
What does the tildes do in `(~[~[~[~[A, B], C], D], E])`?

~~~
terhechte
It's a wrapper over a sequence of matches: [http://www.scala-
lang.org/api/current/#scala.util.parsing.co...](http://www.scala-
lang.org/api/current/#scala.util.parsing.combinator.Parsers$$tilde)

Given p1: Parser[A] and p2: Parser[B], a parser composed with p1 ~ p2 will
have type Parser[~[A, B]]. The successful result of the parser can be
extracted from this case class.

In this case it will use the [[[[A,B] C] D] E] sequence to compose A,B,C,D,E
together in order to produce F (A-F are types). At least if I understand
things correctly, I've never used flatten5.

------
ygra
A lifesaver sometimes: [http://cdecl.org](http://cdecl.org)

------
jdkaplan
Related:
[http://c-faq.com/decl/spiral.anderson.html](http://c-faq.com/decl/spiral.anderson.html)

------
ajarmst
Doesn't mention the standard "read it backwards to get the type", and
consequently recommends "const int" over the superior "int const".

int * const __p;

Is clearly a pointer to pointer to constant pointer to int. (Hint: read from
right to left). This is made easier if you always put the const modifier to
the right when it is optional.

And just never, ever mix commas with pointer declarations.

~~~
anonymous
HN ate your \\* symbols. Try prefixing the line with 4 spaces to trigger code
formatting.

------
gtani
Yup, we need periodic reminders (and Koenig's C Traps/Pitfalls book, which was
published in, yes, 1989.

[http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html](http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html)

[https://news.ycombinator.com/item?id=5079787](https://news.ycombinator.com/item?id=5079787)

~~~
gngeal
My memory may be faulty, but isn't this also a significant material in K&R?
That would make it almost as old as dirt.

------
ecosse
Worth noting that int&& is not illegal in C++11 since it specifies an rvalue
reference, essentially for efficient move operations.
[http://thbecker.net/articles/rvalue_references/section_03.ht...](http://thbecker.net/articles/rvalue_references/section_03.html)

