commit 758bc2aefe83dace0b03214ee4753d142ecb40f0 Author: Wu Ye Date: Tue Mar 12 23:40:34 2013 +0800 Add list of content Add part of sample code. diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..412eeda --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp +*.sln merge=union +*.csproj merge=union +*.vbproj merge=union +*.fsproj merge=union +*.dbproj merge=union + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ebd21a --- /dev/null +++ b/.gitignore @@ -0,0 +1,163 @@ +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +################# +## Visual Studio +################# + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +.builds +*.dotCover + +## TODO: If you have NuGet Package Restore enabled, uncomment this +#packages/ + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# ReSharper is a .NET coding add-in +_ReSharper* + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Others +[Bb]in +[Oo]bj +sql +TestResults +*.Cache +ClientBin +stylecop.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + + +############# +## Python +############# + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +# Mac crap +.DS_Store diff --git a/CppTemplateTutorial.cpp b/CppTemplateTutorial.cpp new file mode 100644 index 0000000..ea76d73 --- /dev/null +++ b/CppTemplateTutorial.cpp @@ -0,0 +1,705 @@ +#include "stdafx.h" +#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.3 Instanciating 2 +namespace _1_3 +{ + 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::? +} + +// 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; +} + diff --git a/CppTemplateTutorial.sln b/CppTemplateTutorial.sln new file mode 100644 index 0000000..1aa975a --- /dev/null +++ b/CppTemplateTutorial.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppTemplateTutorial", "CppTemplateTutorial.vcxproj", "{E86AB3E9-316E-4D00-BBA3-B7CEDFA99D62}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E86AB3E9-316E-4D00-BBA3-B7CEDFA99D62}.Debug|Win32.ActiveCfg = Debug|Win32 + {E86AB3E9-316E-4D00-BBA3-B7CEDFA99D62}.Debug|Win32.Build.0 = Debug|Win32 + {E86AB3E9-316E-4D00-BBA3-B7CEDFA99D62}.Release|Win32.ActiveCfg = Release|Win32 + {E86AB3E9-316E-4D00-BBA3-B7CEDFA99D62}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/CppTemplateTutorial.vcxproj b/CppTemplateTutorial.vcxproj new file mode 100644 index 0000000..a780a0f --- /dev/null +++ b/CppTemplateTutorial.vcxproj @@ -0,0 +1,89 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {E86AB3E9-316E-4D00-BBA3-B7CEDFA99D62} + Win32Proj + CppTemplateTutorial + + + + Application + true + v110 + Unicode + + + Application + false + v110 + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + Console + true + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CppTemplateTutorial.vcxproj.filters b/CppTemplateTutorial.vcxproj.filters new file mode 100644 index 0000000..016ec45 --- /dev/null +++ b/CppTemplateTutorial.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md new file mode 100644 index 0000000..b715441 --- /dev/null +++ b/ReadMe.md @@ -0,0 +1,36 @@ + +# C++ Template 进阶指南 + +## 0. 前言 + +## 1. Template的基本语法 + +###1.1 Template Class的基本语法 +###1.2 Template Function的基本语法 +###1.3 整型也可是Template参数 +###1.4 类中类:灵活的模板定义 + +## 2. 模板世界的If-Then-Else:特化与偏特化 +###2.1 实例化/特化类模板:从类模板到可以定义变量的具体类 +###2.2 类模板的匹配规则:特化与部分特化 +###2.3 函数模板的重载、特化与部分特化 +###2.4 技巧单元:模板与继承 + +## 3 拿起特化的武器,去写程序吧! +###3.1 利用模板特化规则实现If-Then-Else与Switch-Case +###3.2 特化可以有多个选择:替换失败并不是一个错误,只是一种可能 +###3.3 技巧单元:获得类型的属性 ———— 类型萃取(Type Traits) + +## 4 用模板写程序吧!骚年! +## 4.1 模板上的递归 +## 4.2 实战单元:元编程的Fibonacci数列 +## 4.3 技巧单元:typename与template的另一种用法 +## 4.4 实战单元:撰写你自己的元编程“函数”库 +## 4.5 实战单元:实现元编程上的数据结构 ———— 以Vector为例 + +## 5 关于模板,你还需要知道的其它常识 +###5.1 Template-Template Class +###5.2 技巧单元:高阶函数 ———— 从函数到函数的组合 +###5.3 实战单元:STL中的Allocator Rebinder + +## 6 结语 \ No newline at end of file diff --git a/stdafx.cpp b/stdafx.cpp new file mode 100644 index 0000000..2851953 --- /dev/null +++ b/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// CppTemplateTutorial.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/stdafx.h b/stdafx.h new file mode 100644 index 0000000..b005a83 --- /dev/null +++ b/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include +#include + + + +// TODO: reference additional headers your program requires here diff --git a/targetver.h b/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include