Step By Step(C++模板基本技巧)

一、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     }

二、基于不同类型模参的模板类之间的赋值:



前面的博客已经提到过,编译器会将不同类型实例化后的模板类视为不同的类型,因此在这种不同的类型之间进行赋值,如果没有提供必要的方法是无法正常编译的,如:

1     template <typename T>
2     class TestClass {
3         ... ...
4     }
5     int main() {
6         TestClass<int> intClass;
7         TestClass<double> doubleClass = intClass;
8     }

上例中的代码是无法成功编译的,因为在C++编译器看来,TestClass和TestClass就是两个完全不同的类型,这样也就无法利用C++编译器自动生成的缺省赋值函数完全这一赋值功能。如何修改才可以达到这一效果呢,见如下代码示例和关键性注释。

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

class TestClass {

... ...

}

对于上面的模板类,其模参类型并没有任何限制,即可以为任意类型,如普通原始类型、类类型,模板类等。而对于要求模参必须要模板类类型的模板类而言,其模参必须是模板类,否则将无法通过编译。如:

template