#include "stdafx.h" #include #include #define WRONG_CODE_ENABLED 0 // 0. Basic Form namespace _0 { template // Old fasion: template class ClassA { T a; T* b; T foo(); void foo2(T const&); }; template class ClassB { int arr[Sz]; }; size_t a = sizeof(ClassB<3>); size_t b = sizeof(ClassB<7>); template void FunctionA(T const& param) { } template T FunctionB() { return T(); } } // 1.1 Nested in Class namespace _1_1 { template // Old fasion: template class ClassA { T a; T* b; T foo(); template void foo2(T const&, U const&); }; } // 1.2 Instanciating 1 namespace _1_2 { _1_1::ClassA a; #if WRONG_CODE_ENABLED _1_1::ClassA b; // Wrong _1_1::ClassA c; // Wrong #endif } // 1.2.2 namespace _1_2_2 { template T Add(T a, T b) { return a + b; } template 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(v); } #endif } // 1.3 Instanciating 2 namespace _1_3 { template class A { public: void foo() { } }; template class B {}; template class C {}; template ::*a)()> class D {}; #if WRONG_CODE_ENABLED template 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 b; #endif } #if WRONG_CODE_ENABLED const char* s = "abc"; template class S { }; void foo2() { S<"abc"> i; } #endif template class ClassB { T* a; }; template class ClassC { T a; }; struct StructA; // Declared but not be defined ClassB d; // Right #if WRONG_CODE_ENABLED ClassC e; // Wrong #endif } // 1.4 Specialization, Partial Specialization, Full Specialization namespace _1_4 { // Prototype of Templates I: Single Parameter template class ClassD { int a; }; // Specialization: Write a pattern for matching template <> class ClassD // 1. template <> 2. ClassD { int b; }; template <> class ClassD { int c; }; // Partial-Specialization: A partial pattern for matching template class ClassD // 1. template 2. ClassD { int d; }; template <> class ClassD // 1. template <> 2. ClassD { int e; }; // Question: // ClassD::? // ClassD::? // ClassD::? // ClassD::? // ClassD::? // ClassD::? // Prototype of Templates II: Multiple Parameter template class ClassE { int a; }; template class ClassE { int b; }; template class ClassE { int c; }; template class ClassE { int d; }; template class ClassE { int e; }; template <> class ClassE { int f; }; // Question: // ClassE::? // ClassE::? // ClassE::? // ClassE::? // ClassE::? // Member function specialization template class ClassF { public: void foo(); }; template void ClassF::foo() { } template <> void ClassF::foo() { } void foo() { ClassF().foo(); ClassF().foo(); } } // 2.1 Function Specialization namespace _2_1 { // Overload is enabled but no partial-specialization template void foo(T const& x) {} template void foo(T& y) {} void foo(int&) {} void foo(int) {} // Specialization or Overloading template <> void foo(bool const& x) {} // Overloading template void foo(T const*) {} template void foo2(T const&, U const&); #if WRONG_CODE_ENABLED template void foo2(int const&, U const&); template void foo2(int const&, U const&); #endif // Overloading - Looks like partial specification template void foo2(int const&, U const&); template void foo2(T const*, U const&); // Don't forgot // T foo(...); // Specialize types which cannot be inferred by parameter template 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(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 class ClassA { T x; }; template class ClassB { T* x; }; template class ClassC: public ClassB { T* x; }; ClassC a; #if WRONG_CODE_ENABLED class ClassC: public ClassA { }; #endif class ClassD: public ClassB { }; // 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 class Equal { public: static bool const value = false; }; template class Equal { public: static bool const value = true; }; bool x = Equal::value; bool y = Equal::value; } // 3.2 SFINAE: Substitution Failure Is Not An Error. namespace _3_2 { class ClassA { }; template struct Mark { char _[Sz]; }; #if WRONG_CODE_ENABLED template Mark<1> TestIncrementAdd(T const& v) { T tmp = v; ++tmp; return Mark<1>(); } template 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 void test(typename T::Marker) { } template void test(T) { } void DoTest() { test(10); // Call #1. test(10); // Call #2. SFINAE for test(T::Marker). } } // 3.3 Application: Type Traits namespace _3_3 { template class is_same; template 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 class is_class { private: // SFINAE template static Accepted test( int U::* ); template static Rejected test(...); public: static const bool value = sizeof( test(0) ) == sizeof(Accepted); }; bool a = is_class::value; bool b = is_class::value; // B* could be convert to D* template class Convertible { private: // Not SFINAE static Accepted test(Dest*); static Rejected test(...); public: static const bool value = sizeof( test(static_cast(NULL)) ) == sizeof(Accepted); }; bool c = Convertible::value; bool d = Convertible::value; bool e = Convertible::value; // B != D using _3_1::Equal; template class is_base_of { public: static bool const value = is_class::value && is_class::value && Convertible::value && !Equal::value; }; bool f = is_base_of::value; bool g = is_base_of::value; bool h = is_base_of::value; bool i = is_base_of::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 class MetaSum { public: static int const value = MetaSum::value + a; }; template class MetaSum { public: static int const value = a; }; int a = MetaSum<1, 10>::value; } // 3.5 Application: Meta-Fibonacci namespace _3_5 { template class Fibonacci { public: static int const value = Fibonacci::value + Fibonacci::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 x; // ??? template ??? class ClassA { public: typedef int NestedType; }; class ClassB { public: typedef ClassA::NestedType NestedType; }; template class ClassC { public: #if WRONG_CODE_ENABLED typedef T::NestedType NestedType; #endif typedef typename T::NestedType NestedType; typedef typename std::vector::iterator iterator; }; class ClassD { public: template class NestedType; }; template class ClassE { public: template class NestedType; }; template class ClassF { #if WRONG_CODE_ENABLED typedef typename T::NestedType NestedType; #endif typedef typename T::template NestedType NestedType; typedef typename ClassE::template NestedType NestedType2; }; ClassC a; ClassF 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 class int_ { public: static int const value = i; }; int a = int_<5>::value; // This trick could work with overloading template void Do(T* obj, int_<2>) { } template void Do(T* obj, int_<1>) { } void foo() { Do( static_cast(nullptr), int_<1>() ); } template void DoAnotherWay(T* obj) { } // Boolean is more useful than integral in general. template class bool_ { public: static bool const value = v; }; typedef bool_ true_; typedef bool_ false_; #if WRONG_CODE_ENABLED // Aha, function cannot support partial specialization. template void DoAnotherWay(T* obj) {} template void DoAnotherWay(T* obj) {} #endif // 2. Operators: // add template class add_ { public: typedef int_ type; static int const value = type::value; }; #if WRONG_CODE_ENABLED // conflict template class add_ { public: typedef int_ type; static int const value = type::value; }; #endif template class add_c { public: typedef int_ 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 class add2_: public int_ { }; 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 class pair_ { typedef HeadT head; typedef TailT tail; }; class Nil; // Try Use It to Definition typedef pair_< int, pair_ > > vector_3; template class make_vector_ { typedef pair_< T0, make_vector_ > type; }; template <> class make_vector_ { typedef Nil type; }; template class vector_: public make_vector_::type { }; typedef vector_ vector3; // Let's meta-program further // // push_back ? tip: push_back::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; }