模板

1、定义函数模板

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 
 5 template <typename T>
 6 int compare(const T &v1, const T &v2)
 7 {
 8     if(v1 < v2)
 9         return -1;
10     if(v2 < v1)
11         return 1;
12     return 0;
13 }
14 
15 int main()
16 {
17     // T is int---compiler instantiates int compare(const int&, const int&)
18     cout << compare(1, 0) << endl;
19     // T is string---compiler instantiates int compare(const string&, const string&)
20     string s1 = "hi", s2 = "world";
21     cout << compare(s1, s2) << endl;
22     system("pause");
23     return 0;
24 }

inline函数模板---注意:模板函数可以用与非模板函数一样的方式声明为 inline。说明符放在模板形参表之后、返回类型之前,不能放在关键字 template 之前

1 // ok:inline specifier follows templacement of inline specifier
2 template <typename T> inline T min(const T&, const T&);
3 // error: incorrect placement f inline specifier
4 inline template <typename T> T min(const T&, const T&);

 定义多个模板形参:

 1 /**
 2  *    编写一个函数模板,接受一个ostream引用和一个值,将该值写入流。用至少四种不同类型调用函数。
 3  *通过写至cout、写至文件和写至stringstream来测试你的程序。
 4  */
 5 
 6 #include <iostream>
 7 #include <string>
 8 #include <fstream>
 9 #include <sstream>
10 using namespace std;
11 
12 template <typename T1, typename T2>
13 T1& print(T1& s, T2 val)
14 {
15     s << val;
16     return s;
17 }
18 
19 int main()
20 {
21     double dval = 0.88;
22     float fval = -12.3;
23     string oristr = "this is a test", desstr;
24     ostringstream oss(desstr);
25     ofstream outFile("result.dat");
26     
27     // 写至 cout
28     print(cout, -3) << endl;
29     print(cout, dval) << endl;
30     print(cout, fval) << endl;
31     print(cout, oristr) << endl;
32     
33     // 写至文件
34     print(outFile, -3) << endl;
35     print(outFile, dval) << endl;
36     print(outFile, fval) << endl;
37     print(outFile, oristr) << endl;
38     outFile.close();
39     
40     // 写至 stringstream
41     print(oss, -3) << endl;
42     print(oss, dval) << endl;
43     print(oss, fval) << endl;
44     print(oss, oristr) << endl;
45     
46     // 将 stringstream 中的字符串输出到cout以进行验证
47     cout << oss.str() << endl; //oss.str()返回的是 string 类型的字符串
48 
49     system("pause");
50     return 0;
51 }

注意:

 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 
 5 template <typename T>
 6 int compare(const T &v1, const T &v2)
 7 {
 8     if(v1 < v2)
 9         return -1;
10     if(v2 < v1)
11         return 1;
12     return 0;
13 }
14 
15 int main()
16 {
17     // Error
18     cout << compare("hi", "world") << endl;
19     /* 这样调用将会出编译错误,因为根据第一个实参"hi" 可将模板形参T推断为char[3],
20     而第二个实参"world"可将模板形参T推断为char[6],T被推断为两个不同的类型,编译器无法实例化。*/
21     
22     system("pause");
23     return 0;
24 }

2、定义类模板

 1 // 编写类似于标准库中 find 算法的模板函数。使用该函数在 vector<int> 和 vector<string>中查找指定值
 2 #include <iostream>
 3 #include <string>
 4 #include <vector>
 5 using namespace std;
 6 
 7 //template <typename InIt, typename T>
 8 template <class InIt, class T>  // 使用 class 或 typename 关键字都可以
 9 InIt findElem(InIt first, InIt last, const T& val)
10 {
11     while(first != last)
12     {
13         if(*first == val)
14             return first;
15         ++first;
16     }
17     return last;
18 }
19 
20 int main()
21 {
22     int ia[] = {1, 2, 3, 4, 5, 6, 7};
23     string sa[] = {"this", "is", "Mary", "test", "example"};
24     vector<int> ivec(ia, ia+7);
25     vector<string> svec(sa, sa+5);
26     
27     vector<int>::iterator itor;
28     if((itor = findElem(ivec.begin(), ivec.end(), 6)) != ivec.end())
29         cout << "found this element: " << *itor << endl;
30     else
31         cout << "no such element" << endl;
32         
33     vector<string>::iterator itor1;
34     if((itor1 = findElem(svec.begin(), svec.end(), "Mary")) != svec.end())
35         cout << "found this element: " << *itor1 << endl;
36     else
37         cout << "no such element" << endl;
38         
39     system("pause");
40     return 0;
41 }

      如果要在函数模板内部使用在类中定义的类型成员,必须在该成员名前加上关键字typename,告诉编译器将该成员当做类型。 

 1 /**
 2  * 编写一个函数,接受一个容器引用并打印该容器的元素,
 3  * 
 4  */
 5 // 代码一:使用容器的 size_type 和 size成员控制打印元素的循环。
 6 #include <iostream>
 7 #include <string>
 8 #include <vector>
 9 using namespace std;
10 
11 template <typename Parm>
12 void print(const Parm& c)
13 {
14     typename Parm::size_type index = 0;
15     while(index != c.size())
16     {
17         cout << c[index] << ' ';
18         ++index;
19     }
20 }
21 
22 int main()
23 {
24     int ia[] = {1, 2, 1, 4, 1, 6, 1};
25     string sa[] ={"this", "is", "Mary", "test", "example"};
26     vector<int> ivec(ia, ia+7);
27     vector<string> svec(sa, sa+5);
28     print(ivec);
29     cout << endl;
30     print(svec);
31     
32     system("pause");
33     return 0;
34 }
35 
36 // 代码二:使用 begin 和 end 返回迭代器来控制循环
37 #include <iostream>
38 #include <string>
39 #include <vector>
40 using namespace std;
41 
42 template <typename Parm>
43 void print(const Parm& c)
44 {
45     typename Parm::const_iterator itor = c.begin();
46     while(itor != c.end())
47     {
48         cout << *itor++ << ' ';
49     }
50 }
51 
52 int main()
53 {
54     int ia[] = {1, 2, 1, 4, 1, 6, 1};
55     string sa[] ={"this", "is", "Mary", "test", "example"};
56     vector<int> ivec(ia, ia+7);
57     vector<string> svec(sa, sa+5);
58     print(ivec);
59     cout << endl;
60     print(svec);
61 
62     system("pause");
63     return 0;
64 }

 模板形参也可以是非类型的:模板非类型形参是模板定义内部的常量值,在需要常量表达式的时候,可使用非类型形参

 例如:编写可以确定数组长度的函数模板

1 template <typename T, std::size_t N>
2 std::size_t size(T (&arr)[N])
3 {
4     return N;
5 }

 对于模板类型形参,传给它的实参必须完全匹配,如果想要用兼容类型调用,可以使用显示模板实参或者强制类型转换(类型转换的限制只适用于类型为模板形参的那些实参,非模板类型的形参可以隐式转换)

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template <typename T>
 5 int compare(const T& v1, const T& v2)
 6 {
 7     if(v1 < v2)
 8         return -1;
 9     if(v2 < v1)    // 注意这里不要写成 v1 > v2, 在泛型编程中注意规范
10         return 1;
11     return 0;
12 }
13 
14 int main()
15 {
16     short sval = 123;
17     int ival = 1024;
18     //cout << compare(sval, ival) << endl;  // ERROR:cannot instantiate compare(short, int), 形参必须完全匹配
19     // 转换类型
20     cout << compare(static_cast<int>(sval), ival) << endl;
21     cout << compare(sval, static_cast<short>(ival)) << endl;
22     // 显示指定形参类型
23     cout << compare<short>(sval, ival) << endl;
24     cout << compare<int>(sval, ival) << endl;
25     
26     system("pause");
27     return 0;
28 }

 一般而言,不会转换实参以匹配已有的实例化,相反,会产生新的实例。除产生新的实例外,编译器只会执行两种转化:

1、const 转换:接收const 引用或 const 指针的函数可以分别用非 const 对象的引用或指针来调用,无须产生新的实例化。如果函数接受非引用类型,形参类型和实参都忽略const,即,无论传递 const 或 非 const 对象给接受非引用类型的函数,都使用相同的实例化。

2、数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指针转换,数组实参将当作指向其第一个元素的指针,函数实参当作指向函数类型的指针。举例说明如下:

 

 1 template <typename T> T fobj(T, T);  // arguments are copied
 2 template <typename T> T fref(const T&, const T&);    // reference argements
 3 
 4 /*
 5     传递 string 对象和 const string 对象作为实参,即使这些类型不完全匹配,两个调用也都是合法的。
 6 在 fobj 的调用中,实参被复制,因此原来的对象是否为 const 无关紧要,在 fref 的调用中,形参类型是
 7 const 引用,对引用形参而言,转换为 const 是可以接受的转换,所以这个调用也正确
 8 */
 9 string s1("a value");
10 const string s2("another value");
11 fobj(s1, s2);    // ok: calls f(string, string), const is ignored
12 fref(s1, s2);    // ok:non const object s1 converted to const reference
13 
14 
15 /*
16      传递不同长度的数组实参--fobj 的调用中,数组不同无关紧要,两个数组都转换为指针,
17 fobj 的模板形参类型是 int*,但是,fref的调用是非法的,当形参为引用时数组不能转换为指针,
18 a 和 b 的类型不匹配(引用类型会检查数组长度),所以调用会出错
19 */
20 int a[10], b[42];
21 fobj(a, b);    // ok: calls f(int*, int*)
22 fref(a, b);    // error:array types don't match; arguments aren't converted to pointers

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值