I'm something of a collector of C++ esoterica. So for CppCon 2018, I thought it'd be fun to set a challenge to try to collect some more examples of "interesting"-but-valid C++ code:
I'm running a mini contest during this year's @CppCon! Show me the most awful, surprising, horrific, inventive, well-formed C++ construct you can fit in a tweet. Best entry as judged by me wins an iPad. #cppcon #cppcon2018
— Richard Smith (@zygoloid) September 24, 2018
I received over forty entries (most on twitter, with one supplied by email), covering a wide spectrum of awful and awesome constructs. Thanks to everyone who participated!
It seems there are some common themes that people liked to explore; here's a rundown of some of those themes:
Some people really don't like certain parts of C++.
std::court << std::endl;
— Alisdair Meredith (@AlisdairMered) September 24, 2018
std::initializer_list
— Vittorio Romeo (@supahvee1234) September 26, 2018
Typo aside, these entries make valid points: both features are easily
misused in various terrible ways, and in the case of initializer_list
, it
fails to support fundamental parts of modern C++ design, such as move semantics
(and likewise list initialization doesn't support perfect forwarding).
The semicolon at the end of each and every expression.
— Apple Tree Mag (SDL) (@stephanedeluca) September 24, 2018
OK, but popular languages with curly-brace syntax have made worse choices.
otherwise,
— Syahmi SHM (@shahmiBro) September 27, 2018
template alias name is its my other alternatives;
template <typename...> using voidify = void;
Alias templates definitely have some surprising cases, and this (now known as
std::void_t
) is a special case of one of them: alias templates that don't use
some or all of their template parameters are weird.
Some entries want to make future developers' lives miserable with macros.
# define true (rand() > 10)
— Arjen Kılıç (@arjnklc) September 25, 2018
Happy debugging.
#define if(x) if((x) && rand())
— Jon Simantov (@JonSimantov) September 25, 2018
It'll almost never matter....
inline T distance_0(const calc<T>& O){
— Jonatan W (@jawrxu) September 24, 2018
#define x (x0+(x3-x0)*.5)
#define y (y0+(y3-y0)*.5)
#define ox (O.x0+(O.x3-O.x0)*.5)
#define oy (O.y0+(O.y3-O.y0)*.5)
return sqrt(pow((ox-x),2.0)+pow((oy-y),2.0));
#undef x
#undef y
#undef ox
#undef oy
}
int main()
— LokiAstari (@LokiAstari) September 24, 2018
{
[](){}();
}
I have always been fascinating by how simple lambdas could be:
— Michele C. S. (@michelinux) September 26, 2018
[](){}();
Which actually compiles.
Lambdas can of course be simpler: []{}
is sufficient.
Sadly we missed the chance in C++20 of allowing []<>(){}
-- you need to
declare at least one template parameter in a generic lambda with an explicit
template parameter list.
Some decided to submit entries that ignore the "well-formed" requirement. That's OK; I encourage bending (or in this case, entirely breaking) the rules. Others just had minor typos in their examples.
class X {};
— Peter Goodman (@peter_a_goodman) September 29, 2018
class Y {};
class B {
public:
virtual ~B() = default;
virtual int M(X &);
virtual int M(Y &);
};
class D : public B {
public:
virtual ~D() = default;
int M(X &) override;
};
int Z(Y &y, D &d) {
return d.M(y);
}
Name hiding does not play nicely with virtual function overrides. For more fun, if we had
class Y : X {};
... then the code would compile and would call D::M(X &)
, rather than B::M(Y &)
.
// gcc-trunk compiles this :Р
— Eugene Velesevich (@EVelesevich) September 27, 2018
template <typename R>
struct B {
B(R) {}
typedef int t(R);
template <typename U>
t B;
};
template <>
template <>
int B<int>::B<int>(int) {
// it's a methstructor!
}
int main() {
B<int>(0).B<int>(0);
}
matthewbg's law tells us that all software is terrible. Compilers are software; the conclusion is obvious. A lesser compiler would crash after its initial mistake, but not this one -- it finds a way to make it work.
int main()
— LokiAstari (@LokiAstari) September 25, 2018
{
// URL valid in source :-)
http∶//AmazingSite.com/C++/CoolSyntax
// Note: to work on twitter a small cheat to stop URL shortening.
// I replaced the : (colon) with ∶ (ratio symbol) in the tweet.
// To compile you will need a colon
}
"Embedding" a URL in source code like this works because the http:
part is taken as a goto
label, and the //
begins a line comment.
However, a goto
label must be followed by a statement, so this example is actually not valid.
const char main[] ="\xb8\x2a\x00\x00\x00\xc3";https://t.co/Nd4AsBBwCY
— Shafik Yaghmour (@shafikyaghmour) September 24, 2018
Since you allowed a similarly ill-formed one, I will add this one.
const int main[] = { -443987883, 440, 113408, -1922629632, 4149, 899584, 84869120, 15544, 266023168, 1818576901, 1461743468, 1684828783, -1017312735 };
— Ben Harold (@grafcaps) September 24, 2018
Defining main
as something other than a function is not actually valid
(because a program is required to have a main
function, and such a variable
would therefore necessarily constitute an invalid redeclaration of it). This
used to be widely or perhaps universally accepted, but recent versions of both
Clang and GCC reject this.
// foo_ is a string guarded by mutex mu_. Read it safely.
— Aaron Jacobs (@_jacobsa_) September 25, 2018
const std::string f = std::lock_guard<std::mutex>(mu_), foo_;
I believe the intended example here would be more like
const std::string f = (std::lock_guard<std::mutex>(mu_), foo_);
... which holds the lock during the initialization of f
and unlocks it at the end of the declaration.
int main() noexcept(static_cast<bool>(alignof(sizeof(__typeof(std::declval<decltype(__LINE__ || nullptr)>()){})))) {}
— Syahmi SHM (@shahmiBro) September 26, 2018
This declares main
as noexcept(true)
. It also leans heavily on vendor extensions (both alignof
applied to an expression and __typeof
are GNU extensions), but that's not the only non-portable thing happening here: declaring main
as noexcept(true)
is not guaranteed to work in C++17 onwards, because the noexcept
is part of the function type, and the standard doesn't list noexcept function types among the function types that are required to be supported as the type of main
.
Some people found creative ways around the "fits in a tweet" condition. One approach is the godbolt link:
https://t.co/qbz3ARJYHS
— Petr Hons (@HonsPe) September 26, 2018
Aka: lets throw an int from C library callback to interrupt simulation. The int is the error code but it will pass normal catch/throw.
Somewhat more creatively, we have the retweet-of-a-picture-of-the-code strategy:
I’m submitting a most wonderful entry to this C++ contest:https://t.co/AKCuX6Fdiu
— JF Bastien (@jfbastien) September 24, 2018
I believe @foonathan should craft an entry based on his prior efforts. 👌https://t.co/qU2TLOMvr2 pic.twitter.com/j39pSqm1yD
— JF Bastien (@jfbastien) September 26, 2018
... and the link-to-an-article-describing-the-code strategy:
The strlen() function in the string.h library is a piece of marvelous art. It employs vodoo magic, actually.
— Shivam Singhal (@shivasinghal00) September 24, 2018
Won't fit in a tweet but the code is so powerful that it outruns a simple for loop by a great margin. Here: https://t.co/G6d0p0EHF9
... and then there's this:
As for "surprising, inventive and well-formed C++ construct", my vote is forhttps://t.co/ezzdlQll2v
— Kris Kwiatkowski (@_henrycase) September 25, 2018
Not sure he will fit in one twit :)
... but I'm not sure I want to accept entries that mix C++ and D in that way.
Another option is to describe what the entry would be in words rather than code:
Operator overloading is cool if used correctly and if not... OMG. So, few companies ago I've seen code with what we called "long arrow concept". Basically someone did overloading in a way that ---> return pointer which was a pointer to a pointer with a value :)
— Kris Kwiatkowski (@_henrycase) September 25, 2018
void i() {
— JF Bastien (@jfbastien) September 26, 2018
switch (auto k{i}; true)
do if (char j; i) default: ;
else ; while (true);
}
This is an infinite loop. Notable awful properties:
auto k{i}
declares a function pointer because the function name i
decaysi
to bool
in the if
condition; the condition evaluates to true
because the address of i
is not nullswitch
with a non-compound-statement body, and a default:
label nested within an inner control construct (yes, that's valid)do
... while
loop with multiple semicolons insideif
... else
(incidentally, the standard used to require that control flow fall through into the else
statement in that case!)// towards "portable" MS-style structured exceptions
— Tony Van Eerd (@tvaneerd) September 28, 2018
// note that the constructor exits twice!#include <csetjmp>#define __try if(StX x)#define __except(e) else
struct StX
{
int r;
static std::jmp_buf b;
StX()
{
r=setjmp(b);
}
operator bool(){return !r;}
};
This ticks a lot of boxes: use of reserved identifiers, simulating exception handling with setjmp
/ longjmp
, and some light macro abuse. And the worst part is that this also fits into the "almost-useful" category.
Some entries provided code that's both terrible and does (or appears to do) something that looks useful.
template<typename T>
— Jakob Hördt (@_neop) September 25, 2018
struct convert {
template <typename ToType>
constexpr operator ToType() { return static_cast<ToType>(ref); }
constexpr convert(const T& val) : ref{val} {}
private:
const T& ref;
};
int main() {
return convert(0.5); //no annoying warning
}
template <auto V>constexpr bool i(){return *(__PRETTY_FUNCTION__ + 14) >> 6;}
— Jonathan Müller (@foonathan) September 25, 2018
template <class E, size_t ... D>constexpr auto e(index_sequence<D...>){auto r=0;((i<E(D)>() && ++r), ...);return r;}
template <typename E>
constexpr auto enum_size = e<E>(make_index_sequence<32>{});
This one needs some explanation: __PRETTY_FUNCTION__
, on some compilers, will format a non-type template argument of enumeration type using the name of the enumerator when one matches. This snippet counts how many integers in [0, 32) are formatted with such a name, and returns that as the "enum size".
The fact that it appears to work, but gets the wrong answer if enumerators are non-contiguous, repeated, or outside the range [0, 32) grants it extra "awful" points.
template <class...T>
— Björn Fahller (@bjorn_fahller) September 24, 2018
struct any_of{
tuple<T...> v;
any_of(T...t):v{t...}{}
template<class U>
bool operator==(U u){
return apply([&](auto...x){return ((x==u)||...);},v);}
};
template <class...A>
any_of(A...)->any_of<A...>;
auto f=[](auto...x) {return any_of{x...}==0;};
It's hard to say where this falls on the awful/awesome continuum. I wouldn't be surprised if there are branches of mathematics where quantifying a value like this is explored.
Some entries tried to push the C++ lexical rules as far as possible, or maybe a little further:
New Kirby operator:#include <iostream>
— Tony Van Eerd (@tvaneerd) September 25, 2018
template<int N> struct x { x() { std::cout << "poyo"; } };
int main()
{
x <('o')> y;
}
This is reminiscent of the idea of declaring "named operators" by wrapping them in some existing operator token, eg: vec1 *dot* vec2
.
constexpr auto auto = auto<auto,auto,auto,auto,auto,auto,auto>();
— Shafik Yaghmour (@shafikyaghmour) September 25, 2018
Godbolt https://t.co/vaHvNETZn7
All the credit goes to @RichardKogelnig for that one https://t.co/cWo9nwmAZA
C++ permits a handful of non-printing Unicode characters in identifiers. This example sneaks in some U+200B ZERO WIDTH SPACE characters to create identifiers that look like the auto
keyword but are not. Fortunately, Clang has our back.
I’d like to also offer this entry to your contest:https://t.co/Hy3u3LDtMn
— JF Bastien (@jfbastien) September 24, 2018
JF Bastien presents "My Little Lexer: Unicorn is Identifier Character".
#define c̦̰̻̟̰͓͍ơ͓n̪̕s̠͉͎͉͚̞t̘̣͎̯e̯̣͔x̡͙͕͕͈̖͈͈p̲̲̯̲̺r͎̞ constexpr
— nobodyreally (@gamefeast) September 27, 2018
c̦̰̻̟̰͓͍ơ͓n̪̕s̠͉͎͉͚̞t̘̣͎̯e̯̣͔x̡͙͕͕͈̖͈͈p̲̲̯̲̺r͎̞ int N = 42;
For when your code really needs that HP Lovecraft feeling.
Some chose to have fun with C++'s integer promotion and overflow rules, or to otherwise summon the Nasal Demons.
Unexpected undefined behavior on most modern platforms:
— Myria (@Myriachan) September 24, 2018
void Meow()
{
std::uint16_t x = 65535;
x *= x;
}
Undefined behavior on platforms where int=32 and short=16, because * will promote unsigned short to signed int, and then the multiplication overflows signed int.
This is a lovely awful C and C++ quirk.
x *= x
for built-in type is defined in terms of x = x * x
,
and *
performs the usual arithmetic conversions on its operands.
Now, if, as is common across today's implementations, int
is 32 bits wide,
this means both operands are promoted to int
,
and the multiplication results in signed overflow
-- and hence in undefined behavior --
if x > 46340
.
this is my all-time favorite, it prints a different result depending on whether long ranks higher than unsigned#include <iostream>
— John Regehr (@johnregehr) September 24, 2018
int main(void) {
std::cout << (-1L > 1U) << "\n";
return 0;
}
The trick here is that the usual arithmetic conversions care not just about what types you use (long
versus unsigned int
in this case), but also the actual sizes of those types on the target. If both types are the same size (eg, on an LLP64 target), the comparison is performed in unsigned int
, because it can represent larger positive integers. If the types are different sizes (eg, on an LP64 target), the comparison is performed in long
instead.
So, this innocent-looking code manages to non-portably give an answer that is distinctly different from the mathematical answer. I'm working with the C++ committee to fix this, but it's a long and complex path.
Error on Line 0 !!!!#line 4294967295
— Shafik Yaghmour (@shafikyaghmour) September 27, 2018
int main() { return notdefined; }
Obligatory godbolt: https://t.co/aS1v0OiZnH
h/t @CoderCaseyhttps://t.co/Y7sPlzRc1A
A relatively-portable (unsigned) integer overflow in the preprocessor. Pretty swanky.
// Infinite loop?
— Shafik Yaghmour (@shafikyaghmour) September 25, 2018
for (int i = 0; i < 4; ++i)
std::cout << i*1000000000 << std::endl;
Obligatory godbolt https://t.co/D6J3ZtSGKs
and Wandbox https://t.co/MZXJlDsU16https://t.co/U0K2lWVaKO
It's always interesting when a succinct example can demonstrate undefined behavior manifesting in an unusual way. Here, GCC deletes the loop exit condition, because i >= 4
is impossible after multiplying i
by 1000000000 and incrementing it.
Not mine, but:#include <cstdlib>
— Peter Alexander (@Poita_) September 25, 2018
static void (*f)() = nullptr;
void omg() { system("rm -rf /"); }
void not_called() { f = &omg; }
int main() { f(); } // calls omg()
This is, at this point, a classic: some compilers reason that the only way the call to f
can be valid is if not_called
is called first, which means that main
must call omg
. Yes, UB can really wipe your hard drive.
Several people submitted entries playing off the fact that the builtin array subscripting operator is commutative. I received one such entry over email from Lev Minkowski:
int arr[1];
0[arr] = 0;
... along with these:
Also valid C:
— Shafik Yaghmour (@shafikyaghmour) September 24, 2018
int n = sizeof(0)["abcdefghij"]; printf("%d\n", n);https://t.co/TSQClsaTtg
int i = 0; while(putchar(i++["Hello World"]));
— Borislav Stanimirov (@stanimirovb) September 25, 2018
This last entry is, for me, the clear winner in this category. The combination
of reverse array indexing, a postincrement expression before the [
, and
making use of the return value of putchar
is delectable.
Declaring global class within a constructor. It requires a pedantic reading of the standard:
— ofyasy (@cpplearner) September 26, 2018
struct A { void* p; A() : p((struct B*)0) {} };
B* bb;
This is one of the few entries that had me reaching for my copy of the standard draft to double-check the rules. Yes, really, a class type declared in a mem-initializer apparently gets introduced in the innermost enclosing namespace scope (just like a class type declared in the signature of a member function). GCC, Clang, and ICC all get this "wrong", but MSVC follows the spec.
— Shafik Yaghmour (@shafikyaghmour) September 24, 2018
"Of course" this calls the std::basic_string<CharT>::operator=(CharT)
assignment operator.
Why can std::string
be assigned from a char
(given that it can't be constructed from one)?
I have no idea.
There are functions that can't be called, because no syntax exist to do that.
— Piotr Padlewski (@PiotrPadlewski) September 24, 2018
struct Uncallable {
template <typename T>
Uncallable() {
// You have won
}
template <typename T>
operator int() {
// You have won
}
};
This is an odd corner of the language. You never really name a constructor when
calling it, so there's nowhere to provide template arguments. And for a
conversion function, you already have a type after the operator
keyword, so
even if you call it explicitly (a.operator X<int>()
), any template arguments
attach to that type, not to the conversion function.
match<“abc|[0-9]+”>(“1234”);
— Hana Dusíková (@hankadusikova) September 25, 2018
This is a reference to Hana's incredible compile-time regular expression library. Or perhaps it's a lamentation about C++'s lack of support for smart quotes. This is certainly surprising and inventive, but I can't consider it awful and horrific. Sorry Hana! =)
Congratulations to @foonathan, our overall winner, with this entry:
template <auto V>constexpr bool i(){return *(__PRETTY_FUNCTION__ + 14) >> 6;}
— Jonathan Müller (@foonathan) September 25, 2018
template <class E, size_t ... D>constexpr auto e(index_sequence<D...>){auto r=0;((i<E(D)>() && ++r), ...);return r;}
template <typename E>
constexpr auto enum_size = e<E>(make_index_sequence<32>{});
This has everything: it's inventive, appears to be novel (converting
enumeration names to strings via __PRETTY_FUNCTION__
has been done before,
but this takes it a step further), and manages to do it in an awful way that
looks like it works and passes simple tests but is actually very wrong.
Congratulations Jonathan!