Hacker News new | past | comments | ask | show | jobs | submit login
Obscure C++ Features (madebyevan.com)
126 points by burke_holland on April 19, 2013 | hide | past | favorite | 53 comments



The behavior of [] is from C -- it's not a bizarro C++ feature.

The "redefining keywords" is the pre-processor. That's what it does. There isn't anything magic here. Strictly speaking it can be run entirely ahead of the C/C++ compiler, on any file you want. There's no requirement that it is C/C++ - you could use it on a python script (as long as you weren't using # comments anywhere :D )


Definitions of obscure:

1. Not easily distinguished

2. Not readily understandable/expressable

3. Not commonly known

I didn't see the author use the word "bizarro" anywhere, nor make any claims about any of this stuff being weird. He actually presented almost everything in a fairly neutral tone, except when he said that using the preprocessor to override keywords was dangerous (which could be construed as opinion).


It's not an opinion, it's forbidden by the language specification so it's not portable.


>The behavior of [] is from C -- it's not a bizarro C++ feature.

I'd say that a feature of C++ is still a feature of C++ even if the same feature is in C.


The point was probably that it is not obscure; it's what you had to learn when using plain C in the first week.


calling a[5] isn't obscure, but 5[a] sure is!


And the next week, and six months after that, again.


While it's definitely a rarely-used feature, the equivalence a[b] == *(a + b) == b[a] is fundamental to pointer math. Once you grok pointer math, then this is an interesting bit of syntax trivia and should not be forgotten easily.


Except you didn't have to learn it as part of learning C, you didn't have to learn C to learn C++, and I would bet 99% of C and C++ programmers have no idea that 5[p] is valid code.


Moreover, 3[a] appears to be supported solely for backwards compatibility with C since it works only for pointers - you can't do this with classes which define operator[](int).


That's because operator overloading in C++ isn't commutative in general. For integers, 'a + b' is the same as 'b + a', but it's not the same in C++.

For example, I could do:

    class MyClass {int operator+(int a) { return a; }};

    MyClass x;
    x + 1;  // Valid.
    1 + x;  // Type error.
EDIT: My mistake. C++ requires these operators to be nonstatic member functions:

     = -> [] ()
Which, annoyingly enough, means that you can define '+' over types that you haven't implemented, but you can't define [] or =.


There is somewhat of a requirement with the preprocessor - if you redefine a keyword and then include a standard library header it's considered undefined behavior. Maybe that's what the author meant.


C++ contains a syntactical shorthand for simultaneously declaring a variable and branching on its value.

    if (MouseEvent *mouse = dynamic_cast<MouseEvent *>(event))
I think it is a complicated description and a complicated example for saying that the assignment operator (=) returns the value that was assigned.


If this were just

    if (mouse = dynamic_cast<MouseEvent *>(event))
then it would indeed just be an if condition expression that happened to be an assignment.

But the variable is being declared as well, so what's actually going on here is a declaration and an initialiser expression. There is actually new functionality here that needed a bit of language design thought, e.g., the declared variable's scope is the whole if statement, not just the condition expression.


I see this as no different than being able to do

    for (int i = 0; i < len; ++i) { }


Imagine my surprise, getting out of college and trying to use this at my job, when the compiler told me it was invalid! It wasn't obscure to me, but apparently was to the Sun Studio C++ compiler.


It was added in C99, I think.


It was added in C++ before that.


The noteworthy bit is that declarations are valid in the conditional "expression" of if-statements and evaluate to the declared variable. It's imo not obvious that declarations are expressions sometimes.


To be precise, declarations are never expressions - there are two forms of if and while statements in the grammar, one taking an expression and the other a declaration.


There are some problems with that method though.

If, for example, you'd like to reverse the condition, you can't write

    if (!(MouseEvent *mouse = dynamic_cast<MouseEvent *>(event)))
    {}
because a definition is not a general expression, but was only added as an "extra" to allow its use in some cases in conditionals.


Oh, ok I didn't know. So it is indeed a syntactical shorthand for simultaneously declaring a variable and branching.


The '=' above is not an assignment operator, as there is no assigment, it is a declaration. Yes, the following is also valid:

    MouseEvent *mouse;
    if(mouse = dynamic_cast<MouseEvent *>(event)))
but it is not the same thing.


for example int a = b = c = 0;


It is more like int a = int b = int c = 0;


Are these really obscure? I've used most of them.


I was going to say the same thing. I guess I've been doing C++ for too long to consider these obscure. Any nontrivial C++ codebase is likely to have several of these.


That's what I thought, but then that last one... I had no idea.


Obscureness is subjective. In my opinion this article would be worse if 50% of the least obscure features were not presented.


"Alternate operator tokens" - there are more tokens you can use instead of []{} etc. See http://en.wikipedia.org/wiki/Digraphs_and_trigraphs


Re. the "redefining keywords" trick. I know this works with at least some versions of g++. However when I tried doing it in MSVC 2008 I ended up with link errors between the library object files (compiled without the redefinition trick) and the app executable that did use the trick. It looked like MSVC was encoding the visibility in the mangled method names.


The first review I read about the StarOffice source code (now OpenOffice, LibreOffice) back then when it was open sourced was that it was full of #define private public lines


If I remember correctly, it's undefined behavior if you redefine keywords anywhere, not just for library headers as the article suggests.


My favorite is that these are indeed "alternate operator tokens" an so you can use `compl` in place of ~ to name a destructor. Like, for explicit destruction:

    MyType* foo = ...;
    foo->compl MyType();


If there is ever an IOC++CC (International Obfuscated C++ Code Contest), I imagine that this technique will show up all over the place.

Bonus: Can you paste together the "compl" token with preprocessor macros?


I think the only thing "obscure" in this list is the "pointer-to-member" syntax. It's conceptually simple but the syntax is pretty bizarre, hard to remember even when you're searching for it, and probably a lot of C++ programmers working professionally will not recognize it.

I remember a few years ago I was writing some code where using pointer-to-struct-member made lots of sense to me. Doing a code review I was asked politely by a peer to rewrite without them. I disagreed but didn't mind doing so, if it made people on the team happier about readability.


Dark font on dark background. Unreadable.


There are some advantages to the company firewall blocking style sheets.


Sorry, I know I'm drifting massively off topic now, but why on earth would any company adopt such a policy? It's not even as if CSS files can carry executable code (sure, they can reference such content, but then block that stuff instead of the style sheets themselves).


Discourage browsing?


Indeed. In Firefox I do View -> Page Style -> No Style.

Alas, this site is not an exception. Many websites sacrifice readability to some graphic designers' whim.


Don't the mainstream browsers support custom styling yet? Like say, a high contrast style?


In Opera, "Page > Style > User Mode" does the trick. I know FF and IE have similar functionality, but I don't know the shortcut.


"Page > Style > High Contrast" will get you high contrast while preserving layout.


Yeah, opera is why I said mainstream. I haven't used anything other than opera in so long that I don't really know which features firefox and chrome still haven't copied yet.


Perl eats C++'s "most vexing parse" for breakfast.


Obscure? You may think so but sometimes these things buy you lots of time.


Yes. Time in a rubber room.


Although the article's interesting (hardly new info, but concisely described), the ghetto antialiasing, - or whatever excuse the CSS-writer had in mind for gray-on-gray text - really hurts legibility. Seriously, high contrast is the answer - look at 95%+ of all books (white on black is high contrast but costs a lot more in ink, so books only typically have white on black).

Back to the content, C++ syntax has always been a bit nasty, and the try/catch for constructor initializers adds yet another wart. It makes me miss LISP again.


Here: http://www.cppgm.org I'm learning a lot of this features!


Dark gray text on black background. Really?


Oh I just love C++ better!


i didn't find any of these things obscure. that tells me that the road to recovery for ex-c++ programmers is a long one. one day at a time.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: