From 758bc2aefe83dace0b03214ee4753d142ecb40f0 Mon Sep 17 00:00:00 2001 From: Wu Ye Date: Tue, 12 Mar 2013 23:40:34 +0800 Subject: [PATCH] Add list of content Add part of sample code. --- .gitattributes | 22 + .gitignore | 163 +++++++ CppTemplateTutorial.cpp | 705 ++++++++++++++++++++++++++++ CppTemplateTutorial.sln | 20 + CppTemplateTutorial.vcxproj | 89 ++++ CppTemplateTutorial.vcxproj.filters | 33 ++ ReadMe.md | 36 ++ stdafx.cpp | 8 + stdafx.h | 15 + targetver.h | 8 + 10 files changed, 1099 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CppTemplateTutorial.cpp create mode 100644 CppTemplateTutorial.sln create mode 100644 CppTemplateTutorial.vcxproj create mode 100644 CppTemplateTutorial.vcxproj.filters create mode 100644 ReadMe.md create mode 100644 stdafx.cpp create mode 100644 stdafx.h create mode 100644 targetver.h 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