5 ms·
How to interpret complex C/C++ declarations (2004)
- jdkaplan 13y agoRelated: http://c-faq.com/decl/spiral.anderson.html http://c-faq.com/decl/spiral.anderson.html
- ygra 13y agoA lifesaver sometimes: http://cdecl.org http://cdecl.org
- terhechte 13y agoI 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_ 13y agoWhat does the tildes do in `(~[~[~[~[A, B], C], D], E])`?
- terhechte 13y agoIt's a wrapper over a sequence of matches: http://www.scala-lang.org/api/current/#scala.util.parsing.combinator.Parsers$$tilde http://www.scala-lang.org/api/current/#scala.util.parsing.co... 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.
- gtani 13y agoYup, 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 13y agoMy memory may be faulty, but isn't this also a significant material in K&R? That would make it almost as old as dirt.
- Sharlin 13y agoThe 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 13y agoI'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.
- ajarmst 13y agoDoesn'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.
- ecosse 13y agoWorth 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.html http://thbecker.net/articles/rvalue_references/section_03.ht...