Skip to content

Instantly share code, notes, and snippets.

@uucidl
Last active November 5, 2017 17:40
Show Gist options
  • Save uucidl/c3c8eb99f7ce8848947929ed3f37384b to your computer and use it in GitHub Desktop.
Save uucidl/c3c8eb99f7ce8848947929ed3f37384b to your computer and use it in GitHub Desktop.
CPP monsters
#if _MSC_VER
#define COMPILE_MSVC 1
#endif
#if !defined(COMPILE_MSVC)
#define COMPILE_MSVC 0
#endif
namespace uu_monsters
{
#if PREDECLARE
int some();
#endif
class Monster1
{
public:
// If this function's prototype has not been declared proper in the namespace,
// then the function `some` cannot be called, although it will prevent re-declaration
// in this namespace.
//
// @cpp_standard{
// 11.3.7: A friend function defined in a class is in the (lexical) scope of the
// class in which it is defined. A friend function defined outside the class is not (3.4.1).
// }
// @see: COMPILE_ERROR_A
// @see: COMPILE_ERROR_B
friend int some() { return 42; }
#if COMPILE_MSVC
// MSVC happily compiles this, and allows you to call the monster
// this won't work on GCC/Clang/ICC
static int call_some() {
auto ptr = some;
return ptr();
}
#endif
#if COMPILE_ERROR_C
static int call_some1() {
// this does not work:
return some();
}
#endif
static int call_some2() {
// however redeclaring works:
int some();
return some();
}
};
#if COMPILE_ERROR_A
// does not compile, because it would clash with `some` in the same namespace
// uu_monster.cpp(xx): error C2084: function 'int uu_monsters::some(void)' already has a body
// uu_monster.cpp(yy): note: see previous definition of 'some'
int some() {
return 24;
}
#endif
} // namespace uu_monster
int main(int, char**)
{
#if PREDECLARE
return uu_monsters::some();
#endif
#if COMPILE_ERROR_B
// uu_monster.cpp(zz): error C3861: 'some': identifier not found
// uu_monster.cpp(zz): error C2672: 'uu_monsters::some': no matching overloaded function found
return uu_monsters::some();
#else
#if COMPILE_MSVC
return uu_monsters::Monster1::call_some();
#endif
#endif
return uu_monsters::Monster1::call_some2();
}
struct Foo
{
int a;
};
int main(int argc, char**argv) {
// this looks like we're calling Foo on foo, while it's actually declaring a variable named foo!
// It is inherited from C, where declarations and usages are made symmetric.
Foo(foo);
foo.a = argc;
// See also:
int (a);
(a) = 42;
// One way to avoid this would be to always use the
// new >=c++11 syntax using braces.
Foo foo2{42};
return foo.a;
}
// @quote{@url{http://csapp.cs.cmu.edu/3e/docs/chistory.html}
// For each object of such a composed type, there was already a way to mention the underlying
// object: index the array, call the function, use the indirection operator on the pointer.
// Analogical reasoning led to a declaration syntax for names mirroring that of the expression syntax
// in which the names typically appear. Thus,
//
// int i, *pi, **ppi;
// declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of
// these declarations reflects the observation that i, *pi, and **ppi all yield an int type when used
// in an expression. Similarly,
// int f(), *f(), (*f)();
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment