/*
 *	C++ Extreme Overloading
 *	by Jan Engelhardt <jengelh [at] medozas de>, 2005
 *	http://jengelh.medozas.de/
 */
#include <stdio.h>

class MX;

class MCL {
	public:
	MCL(const char * = NULL, bool = false);

	const char *operator =(MCL *)  { return "assignment"; }
	const char *operator +(MCL *)  { return "addition"; }
	const char *operator -(MCL *)  { return "subtraction"; }
	const char *operator *(MCL *)  { return "multiplication"; }
	const char *operator /(MCL *)  { return "division"; }
	const char *operator %(MCL *)  { return "remainder"; }
	const char *operator +=(MCL *) { return "addition/assignment"; }
	const char *operator -=(MCL *) { return "subtraction/assignment"; }
	const char *operator *=(MCL *) { return "multiplication/assignment"; }
	const char *operator /=(MCL *) { return "division/assignment"; }
	const char *operator %=(MCL *) { return "remainder/assignment"; }
	const char *operator -(void)   { return "negation"; }
	const char *operator ++(int)   { return "postincrement"; }
	const char *operator ++(void)  { return "preincrement"; }
	const char *operator --(int)   { return "postdecrement"; }
	const char *operator --(void)  { return "predecrement"; }

	const char *operator |(MCL *)  { return "binary or"; }
	const char *operator |=(MCL *) { return "binary or/assignment"; }
	const char *operator &(MCL *)  { return "binary and"; }
	const char *operator &=(MCL *) { return "binary and/assignment"; }
	const char *operator ^(MCL *)  { return "binary xor"; }
	const char *operator ^=(MCL *) { return "binary xor/assignment"; }
	const char *operator !(void)   { return "logic not"; }
	const char *operator ||(MCL *) { return "logic or"; }
	const char *operator &&(MCL *) { return "logic and"; }
	const char *operator ~(void)   { return "binary not"; }
	const char *operator ==(MCL *) { return "equality"; }
	const char *operator !=(MCL *) { return "inequality"; }
	const char *operator <(MCL *)  { return "lesser"; }
	const char *operator >(MCL *)  { return "greater"; }
	const char *operator <=(MCL *) { return "lesser or equal"; }
	const char *operator >=(MCL *) { return "greater or equal"; }

	const char *operator *(void)  { return "dereferenced"; }
	const char *operator &(void)  { return "address taken"; }
	        MX *operator ->(void) { return slave; }
/*	?? operator ->*(one argument) { ... } */

	const char *operator ()(void)     { return "function: void"; }
	const char *operator ()(int)      { return "function: int"; }
	const char *operator ()(int, int) { return "function: int, int"; }
	const char *operator ()(char *s)  { return s; }

	const char *operator [](int)     { return "array member"; }
	const char *operator [](char *s) { return s; }

	operator int         (void) { return 0xC0FFEE; }
	operator char *      (void) { return "cast to char *"; }
	operator const char *(void) { return "cast to const char *"; }
	operator MCL *       (void) { return this; }

	const char *operator ,(int) { return "chained"; }

	MX *slave;
	const char *string;
};

class MX : public MCL {
	public:
	MX(const char *s, bool w = false) : MCL(s, w)
	{
		qwert = s;
	}

	const char *qwert;
};

MCL::MCL(const char *s, bool w)
{
	string = s;
	if (w)
		slave = new MX("magic pointer");
}

class DE {
	public:
	DE(void) { self = this; }
	DE &operator -(void)      { return *this; }
	DE &operator ++(int)      { return *this; }
	DE &operator ~(void)      { return *this; }
	DE *operator !(void)      { return this; }
	int operator ^(DE *)      { return 0; }
	DE *operator ==(int)      { return this; }
	DE &operator *(void)      { return *this; }
	DE *operator &(void)      { return this; }
	DE *operator ->(void)     { return this; }
	DE &operator ()(int)      { return *this; }
	DE *operator ()(int, int) { return this; }
	DE &operator [](int)      { return *this; }
	DE &operator ,(int)       { return *this; }

	DE *self;
};

class FX {
	public:
	FX(const char *s) { string = s; }
	FX &operator ,(FX &a)              { printf("[comma] "); return a; }
	FX &operator ()(FX &a)             { printf("[oneArg] "); return a; }
	FX &operator ()(FX &a, FX &)       { printf("[twoArg] "); return a; }
	FX &operator ()(FX &a, FX &, FX &) { printf("[threeArg] "); return a; }
	operator const char *(void)        { return string; }

	const char *string;
};

int main(void)
{
	MCL *mcl = new MCL("Nothing!", true), &ref = *mcl;

	printf("ARITHMETIC:\n");
	printf("ref = ptr         = %s\n", ref = mcl);
	printf("ref + ref         = %s\n", ref + ref);
	printf("ref - ref         = %s\n", ref - ref);
	printf("ref * ref         = %s\n", ref * ref);
	printf("ref / ref         = %s\n", ref / ref);
	printf("ref %% ref         = %s\n", ref % ref);
	printf("ref += ref        = %s\n", ref += ref);
	printf("ref -= ref        = %s\n", ref -= ref);
	printf("ref *= ref        = %s\n", ref *= ref);
	printf("ref /= ref        = %s\n", ref /= ref);
	printf("ref %%= ref        = %s\n", ref %= ref);
	printf("-ref              = %s\n", -ref);
	printf("ref++             = %s\n", ref++);
	printf("++ref             = %s\n", ++ref);
	printf("ref--             = %s\n", ref--);
	printf("--ref             = %s\n", --ref);
	printf("\n");

	printf("LOGIC:\n");
	printf("ref | ref         = %s\n", ref | ref);
	printf("ref & ref         = %s\n", ref & ref);
	printf("ref ^ ref         = %s\n", ref ^ ref);
	printf("~ref              = %s\n", ~ref);
	printf("ref || ref        = %s\n", ref || ref);
	printf("ref && ref        = %s\n", ref && ref);
	printf("!ref              = %s\n", !ref);
	printf("ref == ref        = %s\n", ref == ref);
	printf("ref != ref        = %s\n", ref != ref);
	printf("ref <  ref        = %s\n", ref < ref);
	printf("ref >  ref        = %s\n", ref > ref);
	printf("ref <= ref        = %s\n", ref <= ref);
	printf("ref >= ref        = %s\n", ref >= ref);
	printf("\n");

	printf("POINTERS AND STUFF:\n");
	printf("*ref              = %s\n", *ref);
	printf("&ref              = %s\n", &ref);
	printf("ref->             = %s\n", ref->qwert);
	printf("\n");

	printf("AS A FUNCTION:\n");
	printf("ref()             = %s\n", ref());
	printf("ref(0)            = %s\n", ref(0));
	printf("ref(0, 0)         = %s\n", ref(0, 0));
	printf("ref(str)          = %s\n", ref("Hi World"));
	printf("\n");

	printf("AS AN ARRAY:\n");
	printf("ref[0]            = %s\n", ref[0]);
	printf("ref[str]          = %s\n", ref[(char *)"what"]);
	printf("\n");

	printf("TYPE CONVERSION:\n");
	printf("(int)ref          = 0x%X\n", static_cast<unsigned int>(ref));
	printf("(char *)ref       = %s\n", static_cast<char *>(ref));
	printf("(const char *)ref = %s\n", (const char *)ref);
	printf("\n");

	printf("CHAIN:\n");
	printf("(ref,0)           = %s\n", (ref, 0));
	printf("\n");

	DE de;
	printf("Extreme example (see " __FILE__ "): %p\n",
	  &(*de,1)(2)[3](-~de++^(*!de,5)==6,7)->self
	);

	FX fa("fa"), fb("fb"), fc("fc"), fd("fd");
	printf("Comma/Func trace #1: ");
	printf("%s\n", (const char *)(
		(fa, fb)(fc, fd)
	));
	printf("Comma/Func trace #2: ");
	printf("%s\n", (const char *)(
		(fa, fb)((fc, fd))
	));

	printf("Comma/Func trace #3: ");
	printf("%s\n", (const char *)(
		(fa, fb)((fc, fd, fb))
	));

	printf("Comma/Func trace #4: ");
	printf("%s\n", (const char *)(
		(fa, fb)(fc, fd, fb)
	));

	return 0;
}

