CppTemplateTutorial/CppTemplateTutorial.cpp

787 lines
13 KiB
C++

#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 {};
template <float a> class E {};
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
}
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
}
// 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;
}