EMACS & 程序 编程点滴...
泛型编程
- Template Arguments versus Template Parameters
- Class template full specialization
- Class template partial specialization
- Separate compilation model for function template (Exported templates)
- Member templates
- Auto export types by compiler
- Specify function template’s types
- Fun-template explicit specialization
- Class template with friend function
- Class template with friend function(with nest types)
- Template template parameters
- Compile-time Assertions
- Local classes
- Type mapping (int2Type)
- Type mapping (Type2Type)
- Type selection
- Detecting convertibility and Inheritance at compile time
- Traits and Policy Classes
- Templates and Inheritance
- Expression Templates
- Type Classification
- Function Objects and Callbacks
- Template metaprogramming
TOP泛型编程
泛型编程和面向对象编程不同,它并不要求你通过额外的间接层来调用函数,它让你编写完全一般化并可重复使用的算法,其 效率与针对某特定数据类型而设计的算法相同。泛型编程的代表作品STL是一种高效、泛型、可交互操作的软件组件。所谓泛 型(Genericity),是指具有在多种数据类型上皆可操作的含意,与模板有些相似。STL巨大,而且可以扩充,它包含很多计算 机基本算法和数据结构,而且将算法与数据结构完全分离,其中算法是泛型的,不与任何特定数据结构或对象类型系在一起。 STL以迭代器(Iterators)和容器(Containers)为基础,是一种泛型算法(Generic Algorithms)库,容器的存在使这些算法有东 西可以操作。STL包含各种泛型算法(algorithms)、泛型指针(iterators)、泛型容器(containers)以及函数对象(function objects)。STL并非只是一些有用组件的集合,它是描述软件组件抽象需求条件的一个正规而有条理的架构。TOP模板
- 通过使用模板可以使程序具有更好的代码重用性。
- 模板是对源代码进行重用,而不是通过继承和组合重用对象代码,当用户使用模板时,参数由编译器来替换。
- 模板由类模板和函数模板二部分组成,以所处理的数据类型的说明作为参数的类就叫类模板,而以所处理的数据类型的说明作 为参数的函数叫做函数模板。
- 模板参数可以由类型参数或非类型参数组成,类型参数可用class和typename关键字来指明,二者的意义相同,都表示后面的参数名代表一个潜在的内置或用户定义的类型,非类型参数由一个普通参数声明构成。
基本的模板技术
以下罗列出各种模板技术1。
TOPTemplate Arguments versus Template Parameters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
template <typename T, int N> class ArrayInClass { public: T array[N]; }; template <typename T> class Dozen { public: ArrayInClass<T,12> contents; public: void setValue(T value) { for(int i = 0; i< 12; i++) { contents.array[i] = value; } } }; int main() { ArrayInClass<double,10> ad; ad.array[0] = 1.0; Dozen<char> test; test.setValue('A'); return 0; } |
TOPClass template full specialization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
template<class T, class U> int Partial_Test<T,U>::high() { return __t.high() + __u.high(); } template<class T, class U> int Partial_Test<T,U>::weight() { return __t.weight() + __u.weight(); } template<> class Partial_Test<Horse,Cat> { public: int high(); int weight(); Horse __horse; Cat __cat; }; int Partial_Test<Horse,Cat>::high() { return __horse.high()/2 + __cat.high()*3; } int Partial_Test<Horse,Cat>::weight() { return __horse.weight()/2 + __cat.weight()*3; } |
TOPClass template partial specialization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
template<int Base, int Exponent> class XY { public: enum { result_ = Base * XY<Base, Exponent-1>::result_ }; }; template<int Base> class XY<Base, 0> // partial specialization { public: enum { result_ = 1 }; }; int main() { printf("X^Y<5, 4>::result_ = %d\n" , XY<5, 4>::result_); return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
template<class T> class Partial_Test<T,Dog> { public: int high(); int weight(); typedef T type_T; type_T __t; Dog __dog; }; template<class T> int Partial_Test<T,Dog>::high() { return __t.high() + __dog.high()*2; } template<class T> int Partial_Test<T,Dog>::weight() { return __t.weight() + __dog.weight()*3; } |
TOPSeparate compilation model for function template (Exported templates)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// test_export_template.hpp export template <typename T> void fun(T t); //test_export_template.cpp #include "test_export_template.hpp" template <typename T> void fun(T t) { printf("---------%d--------\n",t); } // test_main.cpp #include "test_export_template.hpp" int main() { fun(100); return 0; } |
TOPMember templates
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
template <class T> class Queue { public: // class member template template <class Type> class CL { Type member; T mem; }; public: // function member template template <class Iter> void assign( Iter first, Iter last ) { printf("Queue<T>::assign()\n"); } }; int main() { // nested types Queue<int>::CL<char> c; Queue<int>::CL<long> s; // instantiation of Queue<int> Queue<int> qi; // instantiation of Queue<int>::assign( int *, int * ) int ai[4] = { 0, 3, 6, 9 }; qi.assign(ai, ai+4); return 0; } |
TOPAuto export types by compiler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
template <class T1, class T2, class T3> T1 sum( T2 v2, T3 v3) { return T1(v2+v3); } typedef unsigned int ui_type; ui_type calc( char ch, ui_type ui ) { ui_type (*pf)( char, ui_type ) = &sum< ui_type >; ui_type loc = (*pf)(ch, ui); return loc; } int main() { printf("...%d",calc('c', ui_type(1024))); return 0; } |
TOPSpecify function template’s types
1 2 3 4 5 6 7 8 9 10 11 |
template <class T1, class T2, class T3> T1 sum( T2 op1, T3 op2 ) { /* ... */ return T1(10); } void manipulate( int (*pf)( int,char ) ) { }; void manipulate( double (*pf)( float,float ) ) { }; int main( ) { manipulate( &sum< double, float, float > ); return 0; } |
TOPFun-template explicit specialization
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
template <class T1, class T2, class T3> T1 sum(T2 op1, T3 op2) { printf("generic form\n"); return static_cast<T1>(op1+op2); } template<> double sum<double>(float op1, float op2) { printf("specialization form1\n"); return static_cast<double>(op1+op2); } template<> int sum<int, char, char>(char op1, char op2) { printf("specialization form2\n"); return static_cast<int>(op1+op2); } int main() { int i=5; char c='a'; float f=4.5; double d=6.5; printf("....%d....\n", sum<int>(i, i)); printf("....%f....\n", sum<double>(f, f)); printf("....%d....\n", sum<int>(c, c)); return 0; } |
TOPClass template with friend function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
template <typename T> class A; template <typename T> void get (const A<T>& a); template <typename T> class B; template <typename T> void put (const B<T>& b); template <typename T> class A { friend void get<T>(const A<T>& a); public: A (T i) : _i(i) { front = new B<T>(i); back = new B<T>(i); } ~A() { if (front) { delete front; } if (back) { delete back; } } private: T _i; B<T>* front; B<T>* back; }; template <typename T> void get(const A<T>& a) { printf("------ %d ----- %d -------\n",(a.front),(a.back)); } template <typename T> class B { friend void put<T>(const B<T>& b); public: B (T i) : _item(i), _value(i) { } private: T _item; public: T _value; }; template <typename T> void put(const B<T>& b) { printf("------ %d -------\n",b._item); } int main() { A<int> a1(5); A<float> a2(5.4); A<char> a3('a'); B<long> b1(3); get(a1); get(a2); get(a3); put(b1); return 0; } |
TOPClass template with friend function(with nest types)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
template <typename T> class A; template <typename T> void get (const A<T>& a); template <typename T> class A { friend void get<T>(const A<T>& a); private: class B // nested class { public: B (T i) : _item(i) { } T _item; }; public: A (T i) : _i(i) { front = new B(i); back = new B(i); } ~A() { if (front) delete front; if (back) delete back; } private: T _i; B* front; B* back; }; template <typename T> void get(const A<T>& a) { printf("------ %d ----- %d -------\n",(a.front),(a.back)); } int main() { A<int> a1(5); A<float> a2(5.4); A<char> a3('a'); get(a1); get(a2); get(a3); return 0; } |
TOPTemplate template parameters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
template <typename T> struct CompareCat { T __obj; Cat __cat; bool compare() { return (__obj.weight() - __cat.weight()); } }; template <typename T> struct CompareDog { T __obj; Dog __dog; bool compare() { return (__obj.weight() - __dog.weight()); } }; template <typename T> struct CompareHorse { T __obj; Horse __horse; bool compare() { return (__obj.weight() - __horse.weight()); } }; template <template <class> class Animal> class DogZoo : public Animal<Dog> { public: bool horse_compare() { return Animal<Horse>().compare(); } bool cat_compare() { return Animal<Cat>().compare(); } }; typedef DogZoo<CompareDog> MyDogZoo; int main() { MyDogZoo zoo; printf("---- dog's compare %d --- \n",zoo.compare()); printf("---- horse_compare's compare %d --- \n",zoo.horse_compare()); printf("---- cat_compare's compare %d --- \n",zoo.cat_compare()); return 0; } |
TOPCompile-time Assertions
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
template<bool> struct CompileTimeChecker { CompileTimeChecker(...); }; template<> struct CompileTimeChecker<false> {}; #define STATIC_CHECK(expr, msg)\ {\ class ERROR_##msg {}; \ (void)sizeof(CompileTimeChecker<(expr)>(ERROR_##msg()));\ } template <class To, class From> To safe_reinterpret_cast(From from) { STATIC_CHECK(sizeof(From) <= sizeof(To),Destination_Type_Too_Narrow); return reinterpret_cast<To>(from); } const char *str = "12345\n54321\09999"; struct Dog { const char* name(){ return str; } int age(){ return 10; } }; int main() { Dog dog; void* somePointer = &dog; char c = safe_reinterpret_cast<char>(somePointer); return 0; } |
TOPLocal classes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
template <class T, class P> IAnimal* MakeAnimal(const T& obj, const P& arg) { class Local : public IAnimal { public: Local(const T& obj, const P& arg) : obj_(obj), arg_(arg) {} virtual int weight() { return obj_.weight() + arg_.weight(); } virtual int high() { return obj_.high() + arg_.high(); } private: T obj_; P arg_; }; return new Local(obj, arg); } int main() { Dog dog; Horse horse; IAnimal* panimal = MakeAnimal(dog,horse); printf("---the animal's weight %04x --- \n",panimal->weight()); printf("---the animal's high %04x --- \n",panimal->high()); delete panimal; return 0; } |
TOPType mapping (int2Type)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
template <int v> struct Int2Type { enum { value = v }; }; template <typename T, bool isMul> class NiftyContainer { private: int DoSomething(T* pObj, Int2Type<true>) { return pObj->weight()*pObj->high(); } int DoSomething(T* pObj, Int2Type<false>) { return pObj->weight()/pObj->high(); } public: int DoSomething(T* pObj) { return DoSomething(pObj, Int2Type<isMul>()); } }; int main() { NiftyContainer<Dog,true> dog; NiftyContainer<Horse,false> horse; Dog __dog; Horse __horse; printf("---the animal %04x --- \n",dog.DoSomething(&__dog)); printf("---the animal %04x --- \n",horse.DoSomething(&__horse)); return 0; } |
TOPType mapping (Type2Type)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
template <typename T> struct Type2Type { typedef T OriginalType; }; template <class T, class U> int high(const U& arg, Type2Type<T>) { return arg->high(); } template <class U> int high(const U& arg, Type2Type<Dog>) { Dog dog; return arg->high()+dog.high(); } int main() { Horse __horse; printf("---the animal's high %04x --- \n",high(&__horse,Type2Type<Cat>())); printf("---the animal's high %04x --- \n",high(&__horse,Type2Type<Dog>())); return 0; } |
TOPType selection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
template <bool flag, typename T, typename U> struct Select { typedef T Result; }; template <typename T, typename U> struct Select<false, T, U> { typedef U Result; }; template <typename T, bool isMul> class NiftyContainer { typedef typename Select<isMul, T*, T>::Result ValueType; private: ValueType DoSomething(T* pObj, Int2Type<true>) { return pObj; } ValueType DoSomething(T* pObj, Int2Type<false>) { return *pObj; } public: ValueType DoSomething(T* pObj) { return DoSomething(pObj, Int2Type<isMul>()); } }; int main() { NiftyContainer<Dog,true> dog; NiftyContainer<Horse,false> horse; Dog __dog; Horse __horse; printf("---the animal high %04x --- \n",dog.DoSomething(&__dog)->high()); printf("---the animal high %04x --- \n",horse.DoSomething(&__horse).high()); return 0; } |
TOPDetecting convertibility and Inheritance at compile time
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
template <class T, class U> struct ConversionHelper { typedef char Small; struct Big { char dummy[2]; }; static Big Test(...); static Small Test(U); static T MakeT(); }; template <class T, class U> struct Conversion { typedef ConversionHelper<T, U> H; #ifndef __MWERKS__ enum { exists = sizeof(typename H::Small) == sizeof((H::Test(H::MakeT()))) }; #else enum { exists = false }; #endif enum { exists2Way = exists && Conversion<U, T>::exists }; enum { sameType = false }; }; template <class T> struct Conversion<T, T> { enum { exists = 1, exists2Way = 1, sameType = 1 }; }; template <class T> struct Conversion<void, T> { enum { exists = 0, exists2Way = 0, sameType = 0 }; }; template <class T> struct Conversion<T, void> { enum { exists = 0, exists2Way = 0, sameType = 0 }; }; template <> struct Conversion<void, void> { public: enum { exists = 1, exists2Way = 1, sameType = 1 }; }; template <class T, class U> struct SuperSubclass { enum { value = (Conversion<const volatile U*, const volatile T*>::exists && !Conversion<const volatile T*, const volatile void*>::sameType) }; }; template<class T,class U> struct SuperSubclassStrict { enum { value = (Conversion<const volatile U*, const volatile T*>::exists && !Conversion<const volatile T*, const volatile void*>::sameType && !Conversion<const volatile T*, const volatile U*>::sameType) }; }; #define SUPERSUBCLASS(T, U) \ SuperSubclass<T,U>::value #define SUPERSUBCLASS_STRICT(T, U) \ SuperSubclassStrict<T,U>::value int main() { printf("--- SUPERSUBCLASS test %d --- \n",SUPERSUBCLASS(Dog,IAnimal)); printf("--- SUPERSUBCLASS test %d --- \n",SUPERSUBCLASS(IAnimal,Dog)); printf("--- SUPERSUBCLASS test %d --- \n",SUPERSUBCLASS(Cat,ICat)); printf("--- SUPERSUBCLASS test %d --- \n",SUPERSUBCLASS(ICat,Cat)); printf("--- SUPERSUBCLASS test %d --- \n",SUPERSUBCLASS(Cat,Dog)); printf("--- SUPERSUBCLASS test %d --- \n",SUPERSUBCLASS(Dog,Cat)); return 0; } |
应用于设计的模板技术
TOPTraits and Policy Classes
这里和这里有一些介绍Traits技术的,利用它,我们可以取出类成员类型或是变量。 首先是Type Traits,基本的形式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
struct __true_type {}; struct __false_type {}; template <class T> struct TypeTraits { typedef __true_type this_dummy_member_must_be_first; typedef __false_type has_trivial_default_constructor; typedef __false_type has_trivial_copy_constructor; typedef __false_type has_trivial_assignment_operator; typedef __false_type has_trivial_destructor; typedef __false_type is_POD_type; }; // 一个特化的类型 template<> struct TypeTraits<bool> { typedef __true_type has_trivial_default_constructor; typedef __true_type has_trivial_copy_constructor; typedef __true_type has_trivial_assignment_operator; typedef __true_type has_trivial_destructor; typedef __true_type is_POD_type; }; // partial-specialization的版本 template <class T> struct TypeTraits<T*> { typedef __true_type has_trivial_default_constructor; typedef __true_type has_trivial_copy_constructor; typedef __true_type has_trivial_assignment_operator; typedef __true_type has_trivial_destructor; typedef __true_type is_POD_type; }; |
以下是测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
template <typename T> void __copy(T* destination,const T* source,int size,__false_type) { destination->clone(source); } template <typename T> void __copy(T* destination,const T* source,int size,__true_type) { memcpy(static_cast<void *>(destination),static_cast<const void*>(source),size); } template <typename T> void copy(T* destination,const T* source,int size) { __copy(destination,source,size, typename TypeTraits<T>::has_trivial_copy_constructor()); } class TestClass { private: int _age; char* _name; public: TestClass(): _age(0),_name(NULL) {} ~TestClass() { if (_name) { delete _name; _name = NULL; } } void clone(const TestClass* pobj) { _age = pobj->_age; _name = new char(strlen(pobj->_name)+1); strcpy(_name,pobj->_name); } public: inline void setName(const char* name) { _name = new char(strlen(name)+1); strcpy(_name,name); } inline void setAge(int age) { _age = age; } }; // 测试代码的type_traits特殊化 template<> struct TypeTraits<TestClass> { typedef __true_type has_trivial_default_constructor; typedef __false_type has_trivial_copy_constructor; typedef __false_type has_trivial_assignment_operator; typedef __false_type has_trivial_destructor; typedef __false_type is_POD_type; }; int main() { TestClass test1,test2; test1.setAge(100); test1.setName("the elder"); copy(&test2,&test1,sizeof(test1)); return 0; } |
再看看Iterator Traits:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag {}; struct bidirectional_iterator_tag : public forward_iterator_tag {}; struct random_access_iterator_tag : public bidirectional_iterator_tag {}; // 以下是迭代器的base类型,所有的迭代器需从它继承 template <class _Category, class _Tp, class _Distance = ptrdiff_t, class _Pointer = _Tp*, class _Reference = _Tp&> struct iterator { typedef _Category iterator_category; typedef _Tp value_type; typedef _Distance difference_type; typedef _Pointer pointer; typedef _Reference reference; }; // eg. istreambuf_iterator的实现 template<class _CharT, class _Traits> class istreambuf_iterator : public iterator<input_iterator_tag, _CharT, typename _Traits::off_type, _CharT*, _CharT&> { public: typedef _CharT char_type; typedef _Traits traits_type; typedef typename _Traits::int_type int_type; typedef basic_streambuf<_CharT, _Traits> streambuf_type; typedef basic_istream<_CharT, _Traits> istream_type; public: istreambuf_iterator(streambuf_type* __p = 0); istreambuf_iterator(istream_type& __is); char_type operator*() const; istreambuf_iterator& operator++(); istreambuf_iterator operator++(int); bool equal(const istreambuf_iterator& __i) const; ... }; // iterator_traits template <class _Iterator> struct iterator_traits { typedef typename _Iterator::iterator_category iterator_category; typedef typename _Iterator::value_type value_type; typedef typename _Iterator::difference_type difference_type; typedef typename _Iterator::pointer pointer; typedef typename _Iterator::reference reference; }; // partial-specialization版本 template <class _Tp> struct iterator_traits<_Tp*> { typedef random_access_iterator_tag iterator_category; typedef _Tp value_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef _Tp& reference; }; template <class _Tp> struct iterator_traits<const _Tp*> { typedef random_access_iterator_tag iterator_category; typedef _Tp value_type; typedef ptrdiff_t difference_type; typedef const _Tp* pointer; typedef const _Tp& reference; }; // 利用下面的函数,可以得到迭代器的类型 template <class _Iter> inline typename iterator_traits<_Iter>::iterator_category iterator_category(const _Iter&) { typedef typename iterator_traits<_Iter>::iterator_category _Category; return _Category(); } // 以用下面的函数,得到迭代器的distance type template <class _Iter> inline typename iterator_traits<_Iter>::difference_type* distance_type(const _Iter&) { return static_cast<typename iterator_traits<_Iter>::difference_type*>(0); } // 取得迭代器的value type template <class _Iter> inline typename iterator_traits<_Iter>::value_type* value_type(const _Iter&) { return static_cast<typename iterator_traits<_Iter>::value_type*>(0); } // 以下为测试代码 template <class _InputIterator,class T> void __assign( _InputIterator first, _InputIterator last, const T& value, input_iterator_tag) { printf("--------input_iterator_tag -----------\n"); } template <class _OutputIterator,class T> void __assign( _OutputIterator first, _OutputIterator last, const T& value, output_iterator_tag) { printf("--------output_iterator_tag -----------\n"); } template <class _RandomAccessIterator,class T> void __assign( _RandomAccessIterator first, _RandomAccessIterator last, const T& value, random_access_iterator_tag) { printf("--------random_access_iterator_tag -----------\n"); } template <class Iter,class T> void assign( Iter first, Iter last, const T& value) { typedef typename iterator_traits<Iter>::iterator_category _Category; __assign(first,last,value,_Category()); } class test_iterator : public iterator<input_iterator_tag, char> { //........ }; int main() { test_iterator first,last; assign(first, last,100); return 0; } |
TOPTemplates and Inheritance
TOPThe Empty Base Class Optimization (EBCO)
利用C++模板的泛型编程技术中,经常使用空类对象The Empty Base Class Optimization (EBCO)。它们通常只是定义了一些typedef或者是一些成员函数。缺省的被其他类 使用。当然你可以继承它,替换它们的缺省实现来满足自己的需要。正因为是缺省的,所以要做到最轻量,优化。不占用空间 就是空对象的最大特征之一。C++标准库正是利用这一特征来优化许多组件,不至于使代码过于膨胀。例如以下的类:
1 2 3 4 5 6 7 |
template <class T> class allocator { // an empty class . . . static T* allocate(size_t n) { return (T*) ::operator new(n * sizeof T); } . . . }; |
怎样使用这一特征呢? 看以下的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
// 一个空对象 struct Bar { }; // 如果像这样使用空对象,是不可能省下空间的。 // 以下的Baz对象仍旧是8个字节。 // b虽然只占了一个字节,但是因为对齐的原因,实际上是8个字节。 struct Baz { Bar b; int* p; }; // 如果这样使用,那么基类就被认为是空基类,尺寸是0 struct Baz2 : Bar { int* p; }; // 我们已经知道了allocator是个空对象,内嵌类P从allocator继承 // allocator的尺寸是0! // 在容器类list中通过head_成员来分配空间 template <class T, class Alloc = allocator<T> > class list { . . . struct Node { . . . }; struct P : public Alloc { P(Alloc const& a) : Alloc(a), p(0) { } Node* p; }; P head_; public: explicit list(Alloc const& a = Alloc()) : head_(a) { . . . } . . . }; // 我们可以将这个方法用模板封装起来 // 以后在类中声明BaseOpt的对象就可以了 template <class Base, class Member> struct BaseOpt : Base { Member m; BaseOpt(Base const& b, Member const& mem) : Base(b), m(mem) { } }; template <class T, class Alloc = allocator<T> > class list { ... struct Node { . . . }; BaseOpt<Alloc,Node*> head_; public: explicit list(Alloc const& a = Alloc()) : head_(a,0) { . . . } . . . }; |
TOPThe Curiously Recurring Template Pattern (CRTP)
利用The Curiously Recurring Template Pattern (CRTP)可以实现静态的多态。其原理就像是以下的代码,将子类自身作为基类的模板参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
template <typename CountedType> class ObjectCounter { private: static size_t count; // number of existing objects protected: // default constructor ObjectCounter() { ++ObjectCounter<CountedType>::count; } // copy constructor ObjectCounter (ObjectCounter<CountedType> const&) { ++ObjectCounter<CountedType>::count; } // destructor ~ObjectCounter() { --ObjectCounter<CountedType>::count; } public: // return number of existing objects: static size_t live() { return ObjectCounter<CountedType>::count; } }; // initialize counter with zero template <typename CountedType> size_t ObjectCounter<CountedType>::count = 0; template <typename CharT> class MyString : public ObjectCounter<MyString<CharT> > { }; int main() { MyString<char> s1, s2; MyString<wchar_t> ws; printf("number of MyString<char>: %d\n", MyString<char>::live()); printf("number of MyString<wchar_t>: %d\n",ws.live()); return 0; } |
那么这么做在什么情况下适当呢? 我们来看几种它的应用。
TOP不需要虚拟函数的代码再利用
如果想改变某个类成员函数的行为,一般都是将该函数定义为虚函数,在派生类中重载使用。而利用CRTP,我们可以不需要这 个虚函数。比如下面的例子。
1 2 3 4 5 6 7 8 9 10 11 12 |
template<class T> class X { public: static size_t getSize() { return sizeof(T); } }; class A : public X <A> { int x; }; int main() { cout << "sizeof(A) = " << A::getSize() << endl; } |
这里,class A 自体对象生成之前,利用X<A>,X的实例已经被模板化。 在X<A>里面,因为A本身还没有生成,sizeof不是不能使用 吗? 其实,对于类模板来说,只要没有显示的实例化,或者特化(specialization),类自身的成员函数、静态变量不会被 实例化。
从上面的代码看,X<A>实例化的时候,静态的成员函数 getSize() 没有被实例化,所以不需要 class A 之前声明(像是class A; 的前置声明)。 而第一次使用 getSize() 的时候是在 main 函数中,而此时 getSize() 已经被实例化了(main 函数到达 之前)。
如果你在比较早的编译器上(比如g++ 2.95.3)实验这些代码,结果sizeof(A) = 8,而在 g++ 3.2 或者 VC++6.0 上,sizeof(A) = 4。
以下是一个实际的例子,用来实现内存池。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include <new> template<class T, int N> class MemPool { private: static T buffer[N]; static int usedNum; public: static void* operator new( size_t size ) { if (size == sizeof(T)) { if (usedNum < N) { return &buffer[usedNum++]; } else { throw std::bad_alloc(); } } else { return ::operator new(size); } } static void operator delete( void* ptr ) { } static void release() { usedNum = 0; } }; template<class T, int N> T MemPool<T,N>::buffer[N]; template<class T, int N> size_t MemPool<T,N>::usedNum = 0; class Foo : public MemPool<Foo, 100> { // .... }; int main() { Foo* foo = new Foo; // 调用MemPool的operator new delete foo; // 调用MemPool的operator delete // …… Foo::release(); } |
TOP利用Template Method实现代码自动化
例如以下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class C{ public: C operator+(C const &rhs) const { // ... } C &operator+=(C const &rhs) { // ... return *this; } }; C C::operator+(C const &rhs) const { C tmp(*this); tmp += rhs; // 委托operator+= return tmp; } |
利用CRTP的技术,实现其自动化的版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
template<class T> struct addable{ T operator+(T const &rhs) const { T tmp(static_cast<T const &>(*this)); tmp += rhs; return tmp; } }; // 利用CRTP实现派生类 class C : public addable<C> { public: C &operator+=(C const &rhs){ // 实现 return *this; } }; |
我们只用一行代码从addable模板类继承,就实现了 C 类中的 operator+ 。当然,在 C 类中必须实现 operator+= 。用 户实现的不同 operator+= 方法,基于基类的 operator+ 方法自动的表征出来。如果在 addable 部分中提供一些基础类库, 用户可以像定义 class C 一样的方式方便,高效地使用这些类库。
在boost中,像这样使用CRTP的例子很多。boost::operators, boost::iterator_facade, boost::iterator_adaptor等就是。
TOP静态的多态性
理解CRTP的静态多态性,可以看以下的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include <iostream> template<class T> class base{ public: void method(){ as_derived().method(); } protected: T &as_derived(){ return static_cast<T&>(*this); } T const &as_derived() const{ return static_cast<T const &>(*this); } }; class A : public base<A>{ public: void method(){ std::cout << "This is A::method()" << std::endl; } }; class B : public base<B>{ public: void method(){ std::cout << "This is B::method()" << std::endl; } }; template<class T> void some_process(base<T> &r) { r.method(); } int main(int argc, char *argv[]) { A a; some_process(a); B b; some_process(b); return 0; } |
在上面的代码中,some_process 函数根据利用参数r实现的多态。也许看到这里你也许会说,r的多态与利用CRTP实现类base, A, B的没有本质的关系,如果要让 some_process 函数静态的多态,标准的模板就能做到,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class A{ public: void method(){ std::cout << "This is A::method()" << std::endl; } }; class B{ public: void method(){ std::cout << "This is B::method()" << std::endl; } } template<class T> void some_process(T &r) { r.method(); } |
没有错,但是存在必有它的道理。
1 2 3 4 5 6 7 8 9 |
template<class T> void some_process(T &r); { r.method(); } template<class T> void some_process(base<T> &r); { r.method(); } |
先看看来这两种定义有什么区别,1行是针对所有类型T,而第6行的方法是base<T>或者其派生类型的定义。 那么针对所有类型T一定会有 method() 方法吗? 如果我们针对int类型实例化 some_process。那么编译器一定出现一大堆莫 名其妙的错误信息。面对编译器的错误信息,会让你白天摸不着头脑。
再来看看CRTP的实现。应为只针对了base<T>或者其派生类型,那么当其成员中没有 method() 方法时,编译器能给出很清楚 的错误信息。用户可以很快的找到原因并解决。
所以说,这是使用CRTP的原因之一:编译期检测概念不匹配
boost::concept_check中就是使用了这个方法。
另外,针对CRTP的实现方法,我们可以重载 some_process 方法, 譬如:
1 2 3 |
template<class T> void some_process(dog<T> &r); template<class T> void some_process(cat<T> &r); |
当然,我们也可以特化一般的函数模板,但是每种类型都必须这样做,使用模板还有什么意义。
这是使用CRTP的原因之二:限制通用函数名称的导入
TOPParameterized Virtuality
可以利用模板来确定一个类的是否使用虚函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
class NotVirtual { }; class Virtual { public: virtual void foo() { } }; template <typename VBase> class Base : private VBase { public: void foo() { printf("Base::foo()\n"); } }; template <typename V> class Derived : public Base<V> { public: void foo() { printf("Derived::foo()\n"); } }; int main() { Base<NotVirtual>* p1 = new Derived<NotVirtual>; p1->foo(); // calls Base::foo() Base<Virtual>* p2 = new Derived<Virtual>; p2->foo(); // calls Derived::foo() return 0; } |
TOPExpression Templates
在一般的编程语言中,往往是分布计算一个表达式,最后将结构合并。比如 a*b+c/d ,首先计算 a*b 和 c/d,让后将结果相加。 但是,为了优化算法,常常将整个表达式作为一个整体来处理。C++模板中就是利用了Expression Templates来实现该技巧。具体实现就是重载算术符,例如 a*b+c/d 就想 add< mul< var<T>,var<T> >, div< var<T>,var<T> > > 一样在以模板参数的 方式实现了表达式的构造。
例如以下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
template <typename Left, typename Op, typename Right> struct LOR { Left fod; Right rod; LOR(Left p, Right r): fod(p), rod(r) {} double operator[](int i) { return Op::apply(fod[i], rod[i]); } }; template <typename T> class Vtr { private: int length; T * vr; public: Vtr(int n, T * d) { length =n; vr = d; } template <typename Left, typename Op, typename Right> void operator=(LOR<Left, Op, Right > exprn) { for (int i=0; i<length; i++) vr[i] = exprn[i]; }; T operator[](int i) const {return vr[i];} }; struct Multiply { static double apply(double a, double b) {return a*b;} }; struct Addition { static double apply(double a, double b) {return a+b;} }; typedef Vtr<double> Vtr_Double; template <typename Left> LOR<Left, Multiply, Vtr_Double> operator*(Left a, Vtr_Double b) { return LOR<Left, Multiply, Vtr_Double >(a,b); }; template <typename Left> LOR<Left, Addition, Vtr_Double> operator+(Left a, Vtr_Double b) { return LOR<Left, Addition, Vtr_Double >(a,b); }; int main(void) { double a[]={1,2,3,4,5}; double b[]={1,2,3,4,5}; double c[]={1,2,3,4,5}; double d[]={1,2,3,4,5}; double e[]={1,2,3,4,5}; Vtr_Double X(5,a), Y(5, b), Z(5,c), W(5, d), Q(5, e); W = X*Y*Z; Q = X+Y+Z; return 0; } |
比如「+」的情况下:
Vtr_Double A, B, C, D;
D = A + B + C;
= LOR<Vtr_Double, Addition,Vtr_Double>() + C;
= LOR<LOR<Vtr_Double, Addition,Vtr_Double>, Addition,Vtr_Double>();
由此可见,为了中间结果而产生的对象构造,保存,备份等处理被回避,整体处理速度得到提升。但是,这样的模板技巧语法 晦涩,理解起来比较困难。另外很依赖类型的特化,最终代码尺寸会增大。
TOPType Classification
利用Type Classification,我们可以很方便的知道模板的参数类型。
1 2 3 4 5 |
if (TypeT<T>::IsPtrT) { } else if (TypeT<T>::IsClassT) { } |
以下是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
struct One {} ; struct Two { One a[2]; }; template<typename T> static One testFunction(...); template<typename T> static Two testFunction(T (*)[1] ); template<typename T> static One testClass(...); template<typename T> static Two testClass(char T::*); template<typename T,typename C = T> class IsFunctionT { public: enum { Yes = sizeof(testFunction<T>(0)) == sizeof(One) && sizeof(testClass<T>(0)) == sizeof(One) }; enum { No = !Yes }; }; template<typename T> class IsFunctionT<T&> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<> class IsFunctionT<void> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<> class IsFunctionT<void const> { public: enum { Yes = 0 }; enum { No = !Yes }; }; template<typename T> void checkT(T* t) { if (IsFunctionT<T>::Yes) { printf("--------------IsFunction\n"); } else { printf("--------------IsNotFunction\n"); } } int foo(int,int) { return 0; } typedef int (*FUNC)(int,int); typedef void (*FUNC2)(); template<typename T,typename C> void checkT(T C::* t) { if (IsFunctionT<T>::Yes) { printf("--------------IsFunction\n"); } else { printf("--------------IsNotFunction\n"); } } struct B { char a; }; typedef void (B::* ClassFunc)(int,int); typedef char (B::* ClassCharMember); int main() { FUNC p = foo; FUNC2 p2 = NULL; ClassFunc p3 = NULL; ClassCharMember p4 = &B::a; int* a = 0; B* b = 0; checkT(p); checkT(a); checkT(p2); checkT(b); checkT(p3); checkT(p4); checkT(foo); return 0; } |
TOPFunction Objects and Callbacks
STL中,根据function object的功能,可以分三类:Arithmetic、Rational、Logical。Arithmetic的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
// 具有一个参数的基类 template <class _Arg, class _Result> struct unary_function { typedef _Arg argument_type; typedef _Result result_type; }; // 具有二个参数的基类 template <class _Arg1, class _Arg2, class _Result> struct binary_function { typedef _Arg1 first_argument_type; typedef _Arg2 second_argument_type; typedef _Result result_type; }; // 一个参数时的函数对象 template <class _Tp> struct plus : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x + __y; } }; template <class _Tp> struct minus : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x - __y; } }; template <class _Tp> struct multiplies : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x * __y; } }; template <class _Tp> struct divides : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x / __y; } }; template <class _Tp> inline _Tp identity_element(plus<_Tp>) { return _Tp(0); } template <class _Tp> inline _Tp identity_element(multiplies<_Tp>) { return _Tp(1); } template <class Iter, class T> void arithmetic(Iter first, Iter last, T value, typename plus<T> functorobj) { while(first < last) { *first = functorobj(*first,value); first++; } } int main() { int array[4] = { 0, 3, 6, 9 }; arithmetic(array, array+4, 100, plus<int>()); return 0; } |
TOPTemplate metaprogramming
这是一个大东东,慢慢来,先看一个例子,也是最经典的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> using namespace std; template<int N> struct Factorial { enum {V = N * Factorial<N-1>::V}; }; template<> struct Factorial<1> { enum {V = 1}; }; int main(int argc, char* argv[]) { cout << Factorial<12>::V; return 0; } |
1. 参考《C++ Templates - The Complete Guide》, 《Modern C++ Design》