• 模板


    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
  • 相关阅读:
    利用 innodb_force_recovery 解决MySQL服务器crash无法重启问题
    MySQL-5.7复制功能的默认设置改进
    MySQL explain
    MySQL服务器参数
    MySQL参数调优
    Oracle RAC(Real Application Clusters)
    MySQL show processlist 执行状态分析
    MongoDB 高可用集群架构简介
    docker网络
    centos 7.3镜像制作
  • 原文地址:https://www.cnblogs.com/dongsheng/p/3344380.html
Copyright © 2020-2023  润新知