Step By Step(C++模板基本技巧)
[来源] 达内 [编辑] 达内 [时间]2012-09-13
在此之前,我们了解到的有关该关键字的用途更多是针对模板参数的定义。而这里介绍的使用方式则有些不同,主要区别是typename的这种使用方式用于定义或提示编译器,其后修饰的标识符为模板参数中的类型标识符,而不是普通的静态类成员。
一、typename的另一种使用方式:
在此之前,我们了解到的有关该关键字的用途更多是针对模板参数的定义。而这里介绍的使用方式则有些不同,主要区别是typename的这种使用方式用于定义或提示编译器,其后修饰的标识符为模板参数中的类型标识符,而不是普通的静态类成员。见以下代码示例和关键性注释。
1 #include <stdio.h> 2 3 template<typename T> 4 class MyTestClass { 5 public : 6 // 这里的typename是用于通知编译器,其后的MyType是模板T定义的内部类型,从这个代码示例 7 // 中可以看出,不管是在函数参数、返回值还是定义成员变量定义,都要遵守这一语法规则。 8 MyTestClass(typename T::MyType p) : _p(p) { 9 } 10 typename T::MyType GetData() const { 11 return _p; 12 } 13 public : 14 typename T::MyType _p; 15 }; 16 // 在该类中,由于后面的调用需要将其用作MyTestClass的模参,因此他必须typedef名字为MyType的 17 // 内部类型,否则将会导致编译失败。 18 class TemplateParamClass { 19 public : 20 typedef const char * MyType; 21 }; 22 23 int main() { 24 MyTestClass<TemplateParamClass> t("Hello " ); 25 printf(" The data is %s.\n" ,t.GetData()); 26 return 0; 27 }
前面的博客已经提到过,编译器会将不同类型实例化后的模板类视为不同的类型,因此在这种不同的类型之间进行赋值,如果没有提供必要的方法是无法正常编译的,如: < div style="background-color: rgb(245, 245, 245); font-family: 'Courier New'; font-size: 12px; border: 1px solid rgb(204, 204, 204); padding: 5px; overflow: auto; margin: 5px 0px; max-width: 900px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18px; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; " class="cnblogs_code">
1 template <typename T> 2 class TestClass { 3 ... ... 4 } 5 int main() { 6 TestClass<int > intClass; 7 TestClass<double > doubleClass = intClass; 8 }
1 #include <stdio.h> 2 3 template <typename T> 4 class TestClass { 5 public : 6 TestClass(T v) : _value(v) { 7 } 8 template<typename T2> 9 TestClass<T>& operator = (const TestClass<T2>& other) { 10 // 这是编写重载赋值操作符的基本技巧,既不能进行自身对自身的赋值。 11 if ((void*)this == (void *)&other) 12 return *this ; 13 // 需要说明的是,由于other和this是通过不同类型实例化的模板类,因此这里不能 14 // 像普通类那样直接调用other._value。编译器将他们视为不同的类型,所以也就不 15 // 能直接访问其私有变量了。 16 _value = other.getValue(); 17 return * this; 18 } 19 T getValue() const { 20 return _value; 21 } 22 private: 23 T _value; 24 }; 25 26 int main() { 27 TestClass<int > intClass(5); 28 TestClass<double > doubleClass( 6.4); 29 printf("The value before assignment is %f.\n ",doubleClass.getValue()); 30 //此时的T为double,T2为int。 31 doubleClass = intClass; 32 printf(" The value after assignment is %f.\n",doubleClass.getValue()); 33 return 0; 34 } 35 // The value before assignment is 6.400000. 36 //The value after assignment is 5.000000.
所谓的模板的模板参数,是指模板的参数是另外一个模板类。如:
template<typename T>
class TestClass {
... ...
}
& nbsp; 对于上面的模板类,其模参类型并没有任何限制,即可以为任意类型,如普通原始类型、类类型,模板类等。而对于要求模参必须要模板类类型的模板类而言,其模参必须是模板类,否则将无法通过编译。如:
template <template <typename T> class TemplateClass >
class TemplateTemplateClass {
... ...
}
对于上面的模板类,其模参必须是符合template<typename T> class签名的模板类,该类只有一个普通模参。见如下示例代码和关键性注释。 < div style="background-color: rgb(245, 245, 245); font-family: 'Courier New'; font-size: 12px; border: 1px solid rgb(204, 204, 204); padding: 5px; overflow: auto; margin: 5px 0px; max-width: 900px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 18px; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; " class="cnblogs_code">
1 #include <stdio.h> 2 // 该模板类的第二个模板必须是另外一个模板类。 3 template<typename T, template <typename T> class TemplateClass> 4 class TemplateTemplateClass { 5 public : 6 TemplateTemplateClass(const TemplateClass<T>& tempClass) 7 : _internalClass(tempClass) { 8 } 9 void doTest() { 10 _internalClass.doTest(); 11 } 12 private : 13 TemplateClass<T> _internalClass; 14 }; 15 16 template <typename T> 17 class MyTemplateClass { 18 public : 19 void doTest() { 20 printf("This is MyTemplateClassoTest().\n "); 21 } 22 }; 23 24 int main() { 25 MyTemplateClass<int > tempClass; 26 TemplateTemplateClass<int,MyTemplateClass> tempTempClass(tempClass); 27 tempTempClass.doTest(); 28 return 0 ; 29 } 30 // This is MyTemplateClassoTest().