#include "stdafx.h"
#include <vector>
#include <cstdint>

#define WRONG_CODE_ENABLED 0

// 0. Basic Form
namespace _0
{
	template <typename T> // Old fasion: template <class T>
	class ClassA
	{
		T	a;
		T*	b;
		T foo();
		void foo2(T const&);
	};

	template <int Sz>
	class ClassB
	{
		int arr[Sz];
	};

	size_t a = sizeof(ClassB<3>);
	size_t b = sizeof(ClassB<7>);

	template <typename T> void FunctionA(T const& param)
	{
	}

	template <typename T> T FunctionB()
	{
		return T();
	}
}

// 1.1 Nested in Class
namespace _1_1
{
	template <typename T> // Old fasion: template <class T>
	class ClassA
	{
		T	a;
		T*	b;
		T foo();
		template <typename U> void foo2(T const&, U const&);
	};
}

// 1.2 Instanciating 1
namespace _1_2
{
	_1_1::ClassA<int>				a;

	#if WRONG_CODE_ENABLED
	_1_1::ClassA<WhatTheFuck>		b;	// Wrong
	_1_1::ClassA					c;	// Wrong
	#endif
}

// 1.2.2

namespace _1_2_2
{
	template <typename T> T Add(T a, T b)
	{
		return a + b;
	}

	template <typename SrcT, typename DstT> DstT c_style_cast(SrcT v)
	{
		return (DstT)(v);
	}

#if WRONG_CODE_ENABLED
	void foo()
	{
		int  a = 0;
		int  b = 0;
		char c = 0;
		Add(b, c);
	}

	void foo2()
	{
		int v = 0;
		float i = c_style_cast<float>(v);
	}
#endif
}

// 1.3 Instanciating 2
namespace _1_3
{
	template <int i> class A 
	{
	public:
		void foo()
		{
		}
	};
	template <uint8_t a, typename b, void* c> class B {};
	template <void (*a)()> class C {};
	template <void (A<3>::*a)()> class D {};

#if WRONG_CODE_ENABLED
	template <float a> class E {};
#endif

	void foo()
	{
		A<5> a;
		B<7, A<5>, nullptr> b;
		C<&foo> c;
		D<&A<3>::foo> d;
#if WRONG_CODE_ENABLED
		int x = 3;
		A<x> b;
#endif
	}

#if WRONG_CODE_ENABLED
	const char* s = "abc";
	template <char const* s> class S
	{
	};

	void foo2()
	{
		S<"abc"> i;
	}
#endif

	template <typename T>
	class ClassB
	{
		T* a;
	};

	template <typename T>
	class ClassC
	{
		T a;
	};

	struct StructA; // Declared but not be defined
	ClassB<StructA> d;	// Right
#if WRONG_CODE_ENABLED
	ClassC<StructA> e;	// Wrong
#endif
}

namespace _2_2_2
{
	template <typename T> class AddFloatOrMulInt
	{
		static T Do(T a, T b)
		{
			// 在这个例子里面一般形式里面是什么内容不重要,因为用不上
			// 这里就随便给个0吧。
			return T(0);
		}
	};

	// 其次,我们要指定T是int时候的代码,这就是特化:
	template <> class AddFloatOrMulInt<int>
	{
	public:
		static int Do(int a, int b)
		{
			return a * b;
		}
	};

	// 再次,我们要指定T是float时候的代码:
	template <> class AddFloatOrMulInt<float>
	{
	public:
		static float Do(float a, float b)
		{
			return a * b;
		}
	};

	void foo()
	{
		float a(0), b(1);
		float c = AddFloatOrMulInt<float>::Do(a, b);
	}
}

namespace _2_2_3
{
	template <typename T> class TypeToID
	{
	public:
		static int const ID = -1;
	};

	class B {};

	template <> class TypeToID<void ()>;						// 函数的TypeID
	template <> class TypeToID<int[3]>;							// 数组的TypeID
	template <> class TypeToID<int (int[3])>;					// 这是以数组为参数的函数的TypeID
	template <> class TypeToID<int (B::*[3])(void*, float[2])>;	// 我也不知道这是什么了,自己看着办吧。

	template <> class TypeToID<int const * volatile * const volatile>;
}

namespace _2_2_4
{
	template <typename T> struct X {};
	
	template <typename T> struct Y
	{
		typedef X<T> ReboundType;
#if WRONG_CODE_ENABLED
		typedef typename X<T>::MemberType MemberType;
		typedef WTF MemberType3;
#endif

		static void foo()
		{
			X<T> instance0;
			typename X<T>::MemberType instance1;
			WTF instance2
			大王叫我来巡山 - + &
		}
	};

	void foo()
	{
#if WRONG_CODE_ENABLED
		Y<int>::foo();
		Y<float>::foo();
#endif
	}
}

namespace _2_3_3 {
	struct A;
	template <typename T>
	struct X
	{
		void foo(T v) {
			A a;
			a.v = v;
		}
	};

	struct A
	{
		int v;
	};

	int foo2()
	{
		X<int> x;
		x.foo(5);
		return 0;
	}
}

// 1.4 Specialization, Partial Specialization, Full Specialization
namespace _1_4
{
	// Prototype of Templates I: Single Parameter
	template <typename T> class ClassD
	{
		int a;
	};

	// Specialization: Write a pattern for matching
	template <> class ClassD<int>			// 1. template <>			2. ClassD<int>
	{
		int b;
	};
	
	template <> class ClassD<float>
	{
		int c;
	};
	
	// Partial-Specialization: A partial pattern for matching
	template <typename T> class ClassD<T*>	// 1. template <typename T>	2. ClassD<T*>
	{
		int d;
	};
	
	template <> class ClassD<int*>			// 1. template <>			2. ClassD<T*>
	{
		int e;
	};
	
	// Question:
	
	// ClassD<int>::?
	// ClassD<float>::?
	// ClassD<double>::?
	// ClassD<double*>::?
	// ClassD<int*>::?
	// ClassD<int const*>::?
	
	// Prototype of Templates II: Multiple Parameter
	template <typename T, typename U> class ClassE
	{
		int a;
	};
	
	template <typename T, typename U> class ClassE<T, U*>
	{
		int b;
	};
	
	template <typename T> class ClassE<T, int>
	{
		int c;
	};
	
	template <typename T> class ClassE<T, int*>
	{
		int d;
	};
	
	template <typename U> class ClassE<int, U>
	{
		int e;
	};
	
	template <> class ClassE<int, int>
	{
		int f;
	};
	
	// Question:

	// ClassE<float, double>::?
	// ClassE<float, int>::?
	// ClassE<int, float>::?
	// ClassE<int, int*>::?
	// ClassE<int, int>::?

	// Member function specialization
	template <typename T>
	class ClassF
	{
	public:
		void foo();
	};

	template <typename T>
	void ClassF<T>::foo()
	{
	}

	template <> 
	void ClassF<int>::foo()
	{
	}

	void foo()
	{
		ClassF<int>().foo();
		ClassF<float>().foo();
	}
}

// 2.1 Function Specialization
namespace _2_1
{
	// Overload is enabled but no partial-specialization
	template <typename T> void foo(T const& x) {}
	template <typename T> void foo(T& y) {}
	void foo(int&) {}
	void foo(int) {}

	// Specialization or Overloading
	template <> void foo<bool>(bool const& x) {}

	// Overloading
	template <typename T> void foo(T const*) {}

	template <typename T, typename U> void foo2(T const&, U const&);

#if WRONG_CODE_ENABLED
	template <typename U> void foo2<int, U>(int const&, U const&);
	template <typename T, typename U> void foo2<T, U>(int const&, U const&);
#endif

	// Overloading - Looks like partial specification
	template <typename U> void foo2(int const&, U const&);
	template <typename T, typename U> void foo2(T const*, U const&);

	// Don't forgot
	// T foo(...);

	// Specialize types which cannot be inferred by parameter
	template <typename UninferableT, typename InferableT>
	UninferableT foo3(InferableT const&) { return UninferableT(); }

	void test()
	{
		
		int x = 5;
		float y = 10.0f;
		foo(y);
		int const z = 5;
		foo(z);
		foo(true);
		foo3<int>(0.0f);	// Specialize types which is uninferable.

#if WRONG_CODE_ENABLED
		foo(3);	// Ambigous
		foo(x); // Ambigous
#endif
	}
}

// 2.2 Example: Derived from template.
namespace _2_2
{
	template <typename T>
	class ClassA
	{
		T x;
	};

	template <typename T>
	class ClassB
	{
		T* x;
	};
	
	template <typename T>
	class ClassC: public ClassB<T>
	{
		T* x;
	};
	
	ClassC<int> a;

#if WRONG_CODE_ENABLED
	class ClassC: public ClassA<ClassC>
	{
	};
#endif
	
	class ClassD: public ClassB<ClassD>
	{
	};
	
	// ClassC =??= ClassD
}

// 3.1 Meta Switch-Case/If-Then-Else via Specialization
namespace _3_1
{
	bool equal(int a, int b)
	{
		return a == b;
	}
	
	// meta functions:
	// bool equal0(TypeA, TypeB)
	// {
	//		return false;
	// }
	// bool equal1(TypeA, TypeA)
	// {
	//		return true;
	// }
	// equal(A, A) == equal1(A, A) == true
	// euqla(A, B) == equal0(A, B) == false
	template <typename T, typename U>
	class Equal
	{
	public:
		static bool const value = false;
	};
	
	template <typename T>
	class Equal<T, T>
	{
	public:
		static bool const value = true;
	};
	
	bool x = Equal<int, float>::value;
	bool y = Equal<int, int>::value;
}

// 3.2 SFINAE: Substitution Failure Is Not An Error.
namespace _3_2
{
	class ClassA
	{
	};

	template <int Sz> struct Mark
	{
		char _[Sz];
	};

#if	WRONG_CODE_ENABLED
	template <typename T>
	Mark<1> TestIncrementAdd(T const& v)
	{
		T tmp = v;
		++tmp;
		return Mark<1>();
	}

	template <typename T>
	Mark<2> TestIncrementAdd(T const& v)
	{
		return Mark<2>();
	}

	bool a = TestIncrementAdd( ClassA() ) ) == sizeof(Mark<1>);
#endif

	// Right case: From Wiki
	class ClassB
	{
	public:
		typedef int Marker;
	};
 
	template <typename T> void test(typename T::Marker) { }
	template <typename T> void test(T) { }
 
	void DoTest()
	{
		test<ClassB>(10);	// Call #1.
		test<int>(10);		// Call #2. SFINAE for test(T::Marker).
	}
}

// 3.3 Application: Type Traits
namespace _3_3
{
	template <typename T, typename U> class is_same;
	
	
	template <typename B, typename D> class is_base_of;
	// is_base_of
	// 1. B is class, D is also class.
	// 2. D* could be convert to B*
	// 3. B != D

	// Fundamentals
	typedef char Accepted;
	typedef int  Rejected;

	class B
	{
	};

	class D: public B
	{
	};

	class D2: public D
	{
	};

	// Type is a class
	template <typename T>
	class is_class
	{
	private:
		// SFINAE
		template <typename U> static Accepted test( int U::* );
		template <typename U> static Rejected test(...);

	public:
		static const bool value = sizeof( test<T>(0) ) == sizeof(Accepted);
	};

	bool a = is_class<int>::value;
	bool b = is_class<B>::value;

	// B* could be convert to D*
	template <typename Source, typename Dest>
	class Convertible
	{
	private:
		// Not SFINAE
		static Accepted test(Dest*);
		static Rejected test(...);
	public:
		static const bool value = sizeof( test(static_cast<Source*>(NULL)) ) == sizeof(Accepted);
	};

	bool c = Convertible<B, D>::value;
	bool d = Convertible<D, B>::value;
	bool e = Convertible<B, int>::value;

	// B != D
	using _3_1::Equal;

	template <typename Base, typename Derived>
	class is_base_of
	{
	public:
		static bool const value = 
			is_class<Base>::value &&
			is_class<Derived>::value &&
			Convertible<Base, Derived>::value &&
			!Equal<Base, Derived>::value;
	};

	bool f = is_base_of<B, D2>::value;
	bool g = is_base_of<D2, D>::value;
	bool h = is_base_of<B, int>::value;
	bool i = is_base_of<float, int>::value;

	// Questions:
	// remove_reference
	// remove_pointer
	// remove all qualifiers
}

// 3.4 Application: "Recursive" and Meta-Programming
namespace _3_4
{
	// sum a, a+1, ..., b-1, b
	int basic_algo(int a, int b)
	{
		int result = 0;
		for (int i = a; i <= b; ++i)
		{
			result += i;
		}
		return result;
	}

	// Template could not support variable

	// sum [a, b] without variable
	int recursive_algo(int a, int b)
	{
		if (a == b)
		{
			return b;
		}
		return a + recursive_algo(a+1, b);
	}

	// Translate to meta-programming
	template <int a, int b>
	class MetaSum
	{
	public:
		static int const value = MetaSum<a+1, b>::value + a;
	};

	template <int a>
	class MetaSum<a, a>
	{
	public:
		static int const value = a;
	};

	int a = MetaSum<1, 10>::value;
}

// 3.5 Application: Meta-Fibonacci
namespace _3_5
{
	template <int Index>
	class Fibonacci
	{
	public:
		static int const value = Fibonacci<Index - 1>::value + Fibonacci<Index - 2>::value;
	};

	template <>
	class Fibonacci<0>
	{
	public:
		static int const value = 0;
	};

	template <>
	class Fibonacci<1>
	{
	public:
		static int const value = 1;
	};

	int a = Fibonacci<8>::value;
}

// 4   Directive word: typename and template
namespace _4
{
	// typename T::type x;
	// ??? typename ???

	// typename T::template U<type> x;
	// ??? template ???

	class ClassA
	{
	public:
		typedef int NestedType;
	};

	class ClassB
	{
	public:
		typedef ClassA::NestedType NestedType;
	};

	template <typename T>
	class ClassC
	{
	public:
#if WRONG_CODE_ENABLED
		typedef T::NestedType NestedType;
#endif
		typedef typename T::NestedType NestedType;
		typedef typename std::vector<T>::iterator iterator;
	};

	class ClassD
	{
	public:
		template <typename U, typename V> class NestedType;
	};

	template <typename T>
	class ClassE
	{
	public:
		template <typename U> class NestedType;
	};

	template <typename T, typename U>
	class ClassF
	{
#if WRONG_CODE_ENABLED
		typedef typename T::NestedType<U> NestedType;
#endif
		typedef typename T::template NestedType<U, int> NestedType;
		typedef typename ClassE<T>::template NestedType<U> NestedType2;
	};

	ClassC<ClassB> a;
	ClassF<ClassD, float> b;
}

// 5.1 How to Construct Meta Operators
namespace _5_1
{
	// Expression = Value/Data Structure + Operator/Operations

	// Value in Templates:
	//	 Integral Constant (bool, char, unsigned, ...)
	//	 Type (typename)

	// 1. Trick: Constant <--> Type
	template <int i>
	class int_
	{
	public:
		static int const value = i;
	};

	int a = int_<5>::value;

	// This trick could work with overloading
	template <typename T>
	void Do(T* obj, int_<2>)
	{
	}

	template <typename T>
	void Do(T* obj, int_<1>)
	{
	}

	void foo()
	{
		Do( static_cast<int*>(nullptr), int_<1>() );
	}

	template <typename T, int i> void DoAnotherWay(T* obj)
	{
	}

	// Boolean is more useful than integral in general.
	template <bool v>
	class bool_
	{
	public:
		static bool const value = v;
	};

	typedef bool_<true>		true_;
	typedef bool_<false>	false_;
	
#if WRONG_CODE_ENABLED
	// Aha, function cannot support partial specialization.
	template <typename T> void DoAnotherWay<T, 1>(T* obj) {}
	template <typename T> void DoAnotherWay<T, 2>(T* obj) {}
#endif

	// 2. Operators:
	// add
	
	template <typename T, typename U>
	class add_
	{
	public:
		typedef int_<T::value + U::value> type;
		static int const value = type::value;
	};

#if WRONG_CODE_ENABLED
	// conflict
	template <int x, int y>
	class add_
	{
	public:
		typedef int_<x+y> type;
		static int const value = type::value;
	};
#endif
	template <int x, int y>
	class add_c
	{
	public:
		typedef int_<x+y> type;
		static int const value = type::value;
	};

	typedef add_< int_<2>, int_<3> >::type sum;
	int b = sum::value;

	typedef add_< int_<2>, int_<3> >::type sum_c;
	int c = sum_c::value;

	// another solution
	template <typename T, typename U>
	class add2_: public int_<T::value+U::value>
	{
	};
	int d = add2_< int_<2>, int_<3> >::value;

	// Other operators: sub, not, or, and ...
}

// 5.2 Example of Meta Programming: Meta-Vector
namespace _5_2
{
	// Array: elem[count]
	// Meta Array ?

	// Recursively Definition
	// 'Null' terminated
	template <typename HeadT, typename TailT>
	class pair_
	{
		typedef HeadT head;
		typedef TailT tail;
	};

	class Nil;
	
	// Try Use It to Definition
	typedef pair_< int, pair_<float, pair_<double, Nil> > > vector_3;

	template <typename T0, typename T1 = Nil, typename T2 = Nil, typename T3 = Nil>
	class make_vector_
	{
		typedef pair_< T0, make_vector_<T1, T2, T3> > type;
	};

	template <>
	class make_vector_<Nil, Nil, Nil, Nil>
	{
		typedef Nil type;
	};

	template <typename T0, typename T1 = Nil, typename T2 = Nil, typename T3 = Nil>
	class vector_: public make_vector_<T0, T1, T2, T3>::type
	{
	};

	typedef vector_<double, float, int> vector3;

	// Let's meta-program further
	//
	// push_back	?	tip: push_back<Vector, Element>::type
	// pop			?
	// find			?
	// size			?
}

// 6.1 Template-Template Class

// 6.2 High order function, closure and STL allocator rebind

int _tmain(int argc, _TCHAR* argv[])
{
	return 0;
}