精华内容
下载资源
问答
  • 1. 请创建一个数据类型T的链表类模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分)...
  • 类模板模板友元函数定义有2种方式: 1. 将友元模板函数直接定义类模板中。这种方式比较简单直接。 2. 将友元模板函数声明在类模板中,定义类模板之外。这种方式的写法,如果不小心,通常会出现编译没问题,...

    类模板的模板友元函数定义有2种方式:
    1. 将友元模板函数直接定义在类模板中。这种方式比较简单直接。
    2. 将友元模板函数声明在类模板中,定义在类模板之外。这种方式的写法,如果不小心,通常会出现编译没问题,链接时无法解析的错误。
    以下是一个简单的正确的例子:

     1 #include <iostream>
     2 #include <vector>
     3 
     4 template <typename T>
     5 class Number;
     6 
     7 template <typename T>
     8 void print(const Number<T>& n);
     9 
    10 template <typename T>
    11 std::ostream& operator << (std::ostream& os, const Number<T>& n);
    12 
    13 template <typename T>
    14 std::istream& operator>>(std::istream& is, Number<T>& n);
    15 
    16 template <typename T, typename T2>
    17 void printVector(const std::vector<T2>& vt, const Number<T>& n);
    18 
    19 template <typename T>
    20 class Number {
    21 public:
    22     Number(T v) 
    23         : val(v) {}
    24     ~Number() {}
    25 
    26 private:
    27     T val;
    28 public:
    29     friend void print<T> (const Number<T>& n);
    30     friend std::ostream& operator << <T>(std::ostream& os, const Number<T>& n);
    31     friend std::istream& operator>> <T>(std::istream& is, Number<T>& n);
    32 
    33     friend Number<T>& operator += (Number<T>& a, const Number<T>& b)
    34     {
    35         a.val += b.val;
    36         return a;
    37     }
    38     template <typename T2>
    39     friend void printVector<T>(const std::vector<T2>& vt, const Number<T>& n);
    40     template <typename T2>
    41     void memFunc(const std::vector<T2>& vt, const Number<T>& n);
    42 };
    43 
    44 template <typename T>
    45 std::ostream& operator <<(std::ostream& os, const Number<T>& n)
    46 {
    47      os << n.val << std::endl;
    48      return os;
    49 }
    50 
    51 template <typename T>
    52 std::istream& operator >>(std::istream& is, Number<T>& n)
    53 {
    54     is >> n.val;
    55     return is;
    56 }
    57 
    58 template <typename T>
    59 void print<T> (const Number<T>& n)
    60 {
    61     std::cout << n;
    62 }
    63 
    64 template <typename T, typename T2>
    65 void printVector(const std::vector<T2>& vt, const Number<T>& n)
    66 {
    67     for (unsigned int i = 0; i < vt.size(); i++)
    68         std::cout << vt.at(i) << " ";
    69     std::cout << "=> " << n;
    70 }
    71 
    72 template <typename T>
    73 template <typename T2>
    74 void Number<T>::memFunc(const std::vector<T2>& vt, const Number<T>& n)
    75 {
    76     for (unsigned int i = 0; i < vt.size(); i++)
    77         std::cout << vt.at(i) << " ";
    78     std::cout << "=> " << n;
    79 }

    1) 以上代码中,operator +=被定义在类模板内部。其他3个函数先被声明(需提前声明类模板,如果模板函数的参数中含有类模板),然后在类模板中被声明为友元函数, 之后被定义在类模板体之外。
    2) 请注意当模板函数被声明为类模板的友元时,在函数名之后必须紧跟模板实参表,用来代表该友元声明指向函数模板的实例。否则友元函数会被解释为一个非模板函数,链接时无法解析。
    3) 友元模板函数的模板参数类型,并不一定要求是类模板的参数类型,也可以另外声明。

    展开全文
  • 1. 请创建一个数据类型T的链表类模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List<T>& list),根据一个给定的链表构造当前链表(10...
  • C++之——类模板与函数模板用法

    千次阅读 2018-07-13 10:22:41
    类模板针对仅数据成员和成员函数类型不同的。 使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现...

     

    模板是一种对类型进行参数化的工具;
    通常有两种形式:函数模板和类模板;
    函数模板针对仅参数类型不同的函数;
    类模板针对仅数据成员和成员函数类型不同的类。
    使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。模板可以应用于函数和类。下面分别介绍。
    注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
    一、函数模板通式
    1、函数模板的格式:
    template <class 形参名,class 形参名,......>
    返回类型 函数名(参数列表)
    {
    函数体
    }
    其中template和class是关键字,class可以用typename 关键字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。一但声明了模板函数就可以用模板函数的形参名声明类中的成员变量和成员函数,即可以在该函数中使用内置类型的地方都可以使用模板形参名。模板形参需要调用该模板函数时提供的模板实参来初始化模板形参,一旦编译器确定了实际的模板实参类型就称他实例化了函数模板的一个实例。比如swap的模板函数形式为
    template <class T> void swap(T& a, T& b){},当调用这样的模板函数时类型T就会被被调用时的类型所代替,比如swap(a,b)其中a和b是int 型,这时模板函数swap中的形参T就会被int 所代替,模板函数就变为swap(int &a, int &b)。而当swap(c,d)其中c和d是double类型时,模板函数会被替换为swap(double &a, double &b),这样就实现了函数的实现与类型无关的代码。
    2、注意:对于函数模板而言不存在 h(int,int) 这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行 h(2,3) 这样的调用,或者int a, b; h(a,b)。
    二、类模板通式
    1、类模板的格式为:
    template<class  形参名,class 形参名,…>   
    class 类名
    { ... };
    类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如
    template<class T> class A{public: T a; T b; T hy(T c, T &d);};
    在类A中声明了两个类型为T的成员变量a和b,还声明了一个返回类型为T带两个参数类型为T的函数hy。
    2、类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A<int> m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int, double> m;类型之间用逗号隔开。
    3、对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如A<2> m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: 'a' uses undefined class 'A<int>'),类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A<int> m。
    4、在类模板外部定义成员函数的方法为:
    template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
    比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:
    template<class T1,class T2> void A<T1,T2>::h(){}。
    注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。
    5、再次提醒注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。函数模板和类模板;
    函数模板针对仅参数类型不同的函数;
    类模板针对仅数据成员和成员函数类型不同的类。
    使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。模板可以应用于函数和类。下面分别介绍。
    注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
    一、函数模板通式
    1、函数模板的格式:
    template <class 形参名,class 形参名,......>
    返回类型 函数名(参数列表)
    {
    函数体
    }
    其中template和class是关键字,class可以用typename 关键字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。一但声明了模板函数就可以用模板函数的形参名声明类中的成员变量和成员函数,即可以在该函数中使用内置类型的地方都可以使用模板形参名。模板形参需要调用该模板函数时提供的模板实参来初始化模板形参,一旦编译器确定了实际的模板实参类型就称他实例化了函数模板的一个实例。比如swap的模板函数形式为
    template <class T> void swap(T& a, T& b){},当调用这样的模板函数时类型T就会被被调用时的类型所代替,比如swap(a,b)其中a和b是int 型,这时模板函数swap中的形参T就会被int 所代替,模板函数就变为swap(int &a, int &b)。而当swap(c,d)其中c和d是double类型时,模板函数会被替换为swap(double &a, double &b),这样就实现了函数的实现与类型无关的代码。
    2、注意:对于函数模板而言不存在 h(int,int) 这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行 h(2,3) 这样的调用,或者int a, b; h(a,b)。
    二、类模板通式
    1、类模板的格式为:
    template<class  形参名,class 形参名,…>   
    class 类名
    { ... };
    类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如
    template<class T> class A{public: T a; T b; T hy(T c, T &d);};
    在类A中声明了两个类型为T的成员变量a和b,还声明了一个返回类型为T带两个参数类型为T的函数hy。
    2、类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A<int> m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int, double> m;类型之间用逗号隔开。
    3、对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如A<2> m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: 'a' uses undefined class 'A<int>'),类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A<int> m。
    4、在类模板外部定义成员函数的方法为:
    template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
    比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:
    template<class T1,class T2> void A<T1,T2>::h(){}。
    注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。
    5、再次提醒注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

    用类模板实现对任意类型数据的存取实例:

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    struct Student {
    	int id;
    	float gpa;//平均分
    };
    template <class T>
    class Store {//类模板,实现对任意类型数据进行存取
    private:
    	T item;//item用于存放任意类型的数据
    	bool haveValue;//haveValue标记item是否已被存入内容
    public://成员函数用来操作数据成员
    	Store();//构造函数
    	T &getElem();
    	void putElem(const T &x);//存入数据函数
    };
    
    template <class T>//以下是类成员函数模板
    Store<T>::Store():haveValue(false){}//构造函数用来初始化私有数据成员
    template <class T>
    T &Store<T>::getElem() {//注意写法
    	//如试图提取未初始化的数据,则终止程序
    	if (!haveValue) {
    		cout << "No item present!" << endl;
    		exit(1);//使程序完全退出,返回到操作系统
    	}
    	return item;//返回item中存放的数据
    }
    template <class T>
    void Store<T>::putElem(const T &x) {
    	//将haveValue的值置为TRUE,表示item中已存入数组
    	haveValue = true;
    	item = x;//将x存入item
    }
    
    
    int main()
    {
    	Store<int> s1, s2;
    	s1.putElem(3);
    	s2.putElem(-4);
    	cout << s1.getElem() << " " << s2.getElem() << endl;
    
    	Student g = { 1000,23 };
    	Store<Student> s3;
    	s3.putElem(g);
    	cout << "The student id is " << s3.getElem().id << endl;
    	Store<double> d;
    	cout << "Retrieving object D...";
    	cout << d.getElem() << endl;
    	//d未初始化。执行函数D.getelem()导致程序终止
        return 0;
    }
    #include <algorithm>
    #include <iterator>
    #include <vector>
    #include <iostream>
    using namespace std;
    
    template <class T,class InputIterator,class OutputIterator>
    void mySort(InputIterator first, InputIterator last, OutputIterator result) {
    	vector<T> s;
    	for (; first != last; ++first)
    		s.push_back(*first);
    	sort(s.begin(), s.end());
    	copy(s.begin(), s.end(), result);
    }
    int main() {
    	double a[5] = { 1.2,2.4,0.8,3.3,6.6 };
    	//将s数组内容排序后输出
    	mySort<double>(a, a + 5, ostream_iterator<double>(cout, " "));
    	cout << endl;
    	//从标准输入设备输入若干整数,将排序结果输出到输出设备
    	mySort<int>(istream_iterator<int>(cin), istream_iterator<int>(), ostream_iterator<int>(cout, " "));
    	cout << endl;
    	return 0;
    
    }
    

    函数传参:(借鉴原文:https://blog.csdn.net/hudfang/article/details/52934655)

     

    (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

    (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

    (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

    --------------------------------------------------

    如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;
    例1
    int a ;
    const int &ra=a;
    ra=1; //错误
    a=1; //正确
    例2
    string foo( );
    void bar(string & s);
    那么下面的表达式将是非法的:
    bar(foo( ));
    bar(“hello world”);
    原因在于foo( )和”hello world”串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。
    引用型参数应该在能被定义为const的情况下,尽量定义为const 。

    返回值为引用类型的函数某些情况下可作为表达式的左值,而非引用的则一般不可以。
    函数返回值若为引用类型,当返回的是函数的引用形参时,则是对函数外的变量的引用,函数可以作为表达式的左值(被赋予新值)。 
    函数返回值若为引用类型,当返回的是函数的引用形参时,则是对函数外的变量的引用,函数可以作为表达式的左值(被赋予新值)。 
    
    而当函数返回的是非引用类型时,返回的值是函数内隐式生成的临时变量,当函数结束析构时释放,函数作为左值被赋予新值没有意义或产生错误。(例外情况,当返回的是函数中用new等动态内存分配函数建立的指针时,可作为左值。)
    注:“引用类型”并非是一种新的类型,也没有这种类型,只是为了口头上的方便说的,是对某某类型变量的引用的个人说法。而当函数返回的是非引用类型时,返回的值是函数内隐式生成的临时变量,当函数结束析构时释放,函数作为左值被赋予新值没有意义或产生错误。(例外情况,当返回的是函数中用new等动态内存分配函数建立的指针时,可作为左值。)
    注:“引用类型”并非是一种新的类型,也没有这种类型,只是为了口头上的方便说的,是对某某类型变量的引用的个人说法。

     

    展开全文
  • 在看《大化数据结构》的过程中,出现了类模板定义,由于自己c++编写能力并不是很好,自己写了一个类模板,无论怎么写都出现如下错误: 错误 3 error LNK1120: 2 个无法解析的外部命令 F:\leetcode\Sqlist\...

    在看《大化数据结构》的过程中,出现了类模板的定义,由于自己c++编写能力并不是很好,自己写了一个类模板,无论怎么写都出现如下错误:

    错误    3    error LNK1120: 2 个无法解析的外部命令    F:\leetcode\Sqlist\Debug\Sqlist.exe    Sqlist
    错误    1    error LNK2019: 无法解析的外部符号 "public: __thiscall List<int>::List<int>(int * const,int)" (??0?$List@H@@QAE@QAHH@Z),该符号在函数 _wmain 中被引用    F:\leetcode\Sqlist\Sqlist\Sqlist.obj    Sqlist

    但是写一般的类就没问题,搞了半天才知道,类模板的定义与实现最好写在同一个文件中,即声明与实现放到一起,具体为啥减下面的博客:

    https://blog.csdn.net/lichengyu/article/details/6792135

    ***********************************************************************************************************************

    test.h文件:

    #ifndef TEST_H
    #define TEST_H
    #include "stdafx.h"


    template <class DataType>
    class List{
        public:    
            List(DataType a[], int n);
            //~List();
            bool push(DataType a, int n);
        
        private:
            DataType data[10];
            int len;
    };


    #endif

    ***********************************************************************************************************************

    test.cpp文件:

    tem#include "stdafx.h"
    #include "test.h"

    plate<class DataType>
    List<DataType>::List(DataType a[], int n){
        for (int i = 0; i < n; i++){
            data[i] = a[i];
        }
    }

    template<class DataType>
    bool List<DataType>::push(DataType a, int n){
        data[n] = a;
        return 1;
    }

    ***********************************************************************************************************************

    main文件:

    #include "stdafx.h"
    #include "SeqList.h"
    #include "iostream"
    #include "test.h"
    using namespace std;

    int _tmain(int argc, _TCHAR* argv[])
    {
        int a[3] = { 1, 2, 3 };
        /*SeqList<int>list(a,3);
        int data;
        list.GetElem(list, 1, &data);
        cout << "data is :" << data << endl*/;
        List<int> list(a,3);
        //List<int> list;
        list.push(0, 3);

        return 0;
    }
     

    将上述test.cpp中的代码放到test.h中就不会报错了,共勉。
     

    展开全文
  • 类模板三种类模板参数

    千次阅读 2018-04-22 10:40:47
    类模板三种类模板参数 实际上有三种类型模板参数:类型模板参数、模板模板参数(以模板作为模板的参数)、无类型模板参数。 &nbsp; 1、类型模板参数 类型模板参数是我们使用模板的主要目的。我们可以定义多个...

    原文链接:https://www.cnblogs.com/lsgxeva/p/7689995.html

    实际上有三种类型模板参数:类型模板参数、模板模板参数(以模板作为模板的参数)、无类型模板参数。

     

    1、类型模板参数
    类型模板参数是我们使用模板的主要目的。我们可以定义多个类型模板参数:
    template<typename T,typename Container>
    class Grid
    {…}
    同样,也可以为类型模板参数指定默认值:
    #include <iostream>
    using std::vector;
    template<typename T,typename Contianer=vector<T> > //注意空格
    class Grid
    {…}

     

     

    2、模板模板参数(template template parameter)
    就是将一个模板作为另一个模板的参数。
    正如上面的一个例子:
    Grid<int,vector<int> > myIntGrid;
    注意其中int出现了两次,必须指定Grid和vector的元素类型都是int。
    如果写成:
    Grid<int,vector> myIntGrid;
    因为vector本身就是一个模板,而不是一个类型,所以这就是一个模板模板参数。指定模板模板参数有点像在常规的函数中指定函数指针参数。
    函数指针类型包括返回类型和函数的参数类型。在声明模板模板参数的时候也要包括完整的模板声明:
    首先要知道作为参数的模板的原型,比如vector
    template<typename E,typename Allocator=allocator<E> >
    class vector
    {…};
    然后就可以定义:
    template<typename T,template<typename E,typename Allocator=allocator<E> >class Container=vector>
    class Grid
    {
    public:
    //Omitted for brevity
    Container<T>* mCells;
    };
    模板模板参数的一般语法:
    template<other params,…,template<TemplateTypeParams> class ParameterName,other params,…>
    举例一个应用,Grid的一个构造函数:
    template<typename T,template<typename E,typename Allocator=allocator<E> >class Container>
    Grid<T,Container>::Grid(int inWidth,int inHeight):
    mWidth(inWidth),mHeight(inHeight)
    {
    mCells=new Container<T> [mWidth]; //注意此处Container<T>说明,实际上还是说明 Grid<int,vector<int> >
    for(int i=0;i<mWidth;++i)
    mCells[i].resize(mHeight);
    }
    使用的时候,与一般的没有什么区别:
    Grid<int,vector> myGrid;
    myGrid.getElement(2,3);
    注意:不要拘泥于它的语法实现,只要记住可以使用模板作为模板的一个参数。

     

     

    3、无类型模板参数
    无类型模板参数不能是对象,甚至不能是double或者float。无类型参数仅限于int、enmu、指针和引用。
    有时可能想要允许用户指定一个特定值的元素来初始化空对象,可以使用以下的方法:
    template<typename T,const T EMPTY>
    class Grid
    {
    public:
    //Omitted for brevity
    Grid(const Grid<T,EMPTY>& src);
    Grid<T,EMPTY>& operator=( const Grid<T,EMPTY>& rhs);
    //…
    };
    我们可以这样使用:
    Grid<int,10> myIntGrid;
    Grid<int,20> myIntGrid2;
    初始值可以是任意的int数,也就是必须是int、enmu、指针和引用的一种。

    4、指针和引用模板参数
    指针和引用模板参数必须指向所有翻译单元中都可用的全局变量。对于这些类型的变量,相应的技术术语就是带有外部连接的数据。
    使用extern声明即可。
    如:
    template<typename T ,const T& EMPTY>
    class Grid
    {…};
    extern const int emptyInt=0;
    Grid<int,emptyInt> myIntGrid;
    对于初始化我们还可以使用“零初始化”即 T().

     

     

    一、概念

    利用模板特化机制实现编译期条件选择结构,利用递归模板实现编译期循环结构,模板元程序则由编译器在编译期解释执行。

    模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。

      模板是一种对类型进行参数化的工具;

      通常有两种形式:函数模板类模板

      函数模板针对仅参数类型不同的函数

      类模板针对仅数据成员成员函数类型不同的类。

      使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。模板可以应用于函数和类。下面分别介绍。

      注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

    二、通式

    1、函数模板通式

    template <class 形参名,class 形参名,...> 返回类型 函数名(参数列表)
    {
        ... //函数体
    }

    其中template和class是关键字,class可以用typename 关键字代替,在这里typename 和class没区别。

    <>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。一但声明了模板函数就可以在该函数中使用内置类型的地方都可以使用模板形参名。模板形参需要调用该模板函数时提供的模板实参来初始化模板形参,一旦编译器确定了实际的模板实参类型就称他实例化了函数模板的一个实例。比如swap的模板函数形式为

    template <class T> void swap(T& a, T& b){}

    当调用这样的模板函数时类型T就会被被调用时的类型所代替,比如swap(a,b)其中a和b是int 型,这时模板函数swap中的形参T就会被int 所代替,模板函数就变为swap(int &a, int &b)。而当swap(c,d)其中c和d是double类型时,模板函数会被替换为swap(double &a, double &b),这样就实现了函数的实现与类型无关的代码。

    注意:

    对于函数模板而言不存在 h(int,int) 这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行 h(2,3) 这样的调用,或者int a, b; h(a,b)。

     

    2、类模板通式

    template<class  形参名,class 形参名,…> class 类名{
    
    // 类定义... };

    类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如

    template<class T> class A{public: T a; T b; T hy(T c, T &d);};

    在类A中声明了两个类型为T的成员变量a和b,还声明了一个返回类型为T带两个参数类型为T的函数hy。

    对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如A<2> m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: 'a' uses undefined class 'A<int>')类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A<int> m

    在类模板外部定义成员函数的方法为:

    template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体}

    比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:

    template<class T1,class T2> void A<T1,T2>::h(){}

    注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。

    再次提醒注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。

    其中,template 是声明类模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个,可以是类型参数 ,也可以是非类型参数。类型参数由关键字 class或typename 及其后面的标识符构成。非类型参数由一个普通参数构成,代表模板定义中的一个常量。例:

    template<class type,int width>
    
    //type为类型参数,width为非类型参数 class Graphics;

     

    注意:

    (1)如果在全局域中声明了与模板参数同名的变量,则该变量被隐藏掉。

    (2)模板参数名不能被当作类模板定义中类成员的名字。

    (3)同一个模板参数名在模板参数表中只能出现一次。

    (4)在不同的类模板或声明中,模板参数名可以被重复使用。

     

    三、优劣及适用情况

    通过将计算从运行期转移至编译期,在结果程序启动之前做尽可能多的工作,最终获得速度更快的程序。也就是说模板元编程的优势在于:

    1.以编译耗时为代价换来卓越的运行期性能(一般用于为性能要求严格的数值计算换取更高的性能)。通常来说,一个有意义的程序的运行次数(或服役时间)总是远远超过编译次数(或编译时间)。

    2.提供编译期类型计算,通常这才是模板元编程大放异彩的地方。

    模板元编程技术并非都是优点:

    1.代码可读性差,以类模板的方式描述算法也许有点抽象。

    2.调试困难,元程序执行于编译期,没有用于单步跟踪元程序执行的调试器(用于设置断点、察看数据等)。程序员可做的只能是等待编译过程失败,然后人工破译编译器倾泻到屏幕上的错误信息。

    3.编译时间长,通常带有模板元程序的程序生成的代码尺寸要比普通程序的大,

    4.可移植性较差,对于模板元编程使用的高级模板特性,不同的编译器的支持度不同。

    四、技术细节

    模板元编程使用静态C++语言成分,编程风格类似于函数式编程,在模板元编程中,主要操作整型(包括布尔类型、字符类型、整数类型)常量和类型,不可以使用变量、赋值语句和迭代结构等。被操纵的实体也称为元数据(Metadata),所有元数据均可作为模板参数。

    由于在模板元编程中不可以使用变量,我们只能使用typedef名字和整型常量。它们分别采用一个类型和整数值进行初始化,之后不能再赋予新的类型或数值。如果需要新的类型或数值,必须引入新的typedef名字或常量。

    五、其他范例

    // 主模板
    template<int N>
    struct Fib
    {
        enum { Result = Fib<N-1>::Result + Fib<N-2>::Result }; }; // 完全特化版 template <> struct Fib<1> { enum { Result = 1 }; }; // 完全特化版 template <> struct Fib<0> { enum { Result = 0 }; }; int main() { int i = Fib<10>::Result; // std::cout << i << std::endl; } 
    // 仅声明
    struct Nil;
    
    // 主模板
    template <typename T> struct IsPointer { enum { Result = false }; typedef Nil ValueType; }; // 局部特化 template <typename T> struct IsPointer<T*> { enum { Result = true }; typedef T ValueType; }; // 示例 int main() { cout << IsPointer<int*>::Result << endl; cout << IsPointer<int>::Result << endl; IsPointer<int*>::ValueType i = 1; //IsPointer<int>::ValueType j = 1;  // 错误:使用未定义的类型Nil }
    //主模板
    template<bool>
    struct StaticAssert;
    
    // 完全特化 template<> struct StaticAssert<true> {}; // 辅助宏 #define STATIC_ASSERT(exp)\ { StaticAssert<((exp) != 0)> StaticAssertFailed; } int main() { STATIC_ASSERT(0>1); }

     

    参考资料

    [1] http://www.cnblogs.com/salomon/archive/2012/06/04/2534787.html

    [2] http://www.cnblogs.com/assemble8086/archive/2011/10/02/2198308.html

    [3] http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html

     

    一、模板形参概述

    有三种类型的模板形参:类型形参,非类型形参和模板形参。

    二、类型形参

    2.1 、类型模板形参

    类型形参由关见字class或typename后接说明符构成,如template<class T> void h(T a){};其中T就是一个类型形参,类型形参的名字由用户自已确定。模板形参表示的是一个未知的类型。模板类型形参可作为类型说明符用在模板中的任何地方,与内置类型说明符或类类型说明符的使用方式完全相同,即可以用于指定返回类型,变量声明等。

    2.2、 不能为同一个模板类型形参指定两种不同的类型

    比如:

    template<class T>void h(T a, T b){},语句调用h(2, 3.2)将出错,因为该语句给同一模板形参T指定了两种类型,第一个实参2把模板形参T指定为int,而第二个实参3.2把模板形参指定为double,两种类型的形参不一致,会出错。(针对函数模板)

    注意:上面的结论针对函数模板是正确的,但是不适用于类模板。下面将对类模板的情况进行补充。

    当我们声明类对象为:A<int> a,比如template<class T>T g(T a, T b){},语句调用a.g(2, 3.2)在编译时不会出错,但会有警告,因为在声明类对象的时候已经将T转换为int类型,而第二个实参3.2把模板形参指定为double,在运行时,会对3.2进行强制类型转换为3。当我们声明类的对象为:A<double> a,此时就不会有上述的警告,因为从int到double是自动类型转换。

    验证代码如下:

    //TemplateDemo.h
    
    #ifndef TEMPLATE_DEMO_HXX
    #define TEMPLATE_DEMO_HXX
    
    template<class T> class A{ public: T g(T a,T b); A(); }; #endif //TemplateDemo.cpp #include<iostream.h> #include "TemplateDemo.h" template<class T> A<T>::A(){} template<class T> T A<T>::g(T a,T b){ return a+b; } void main(){ A<int> a; cout<<a.g(2,3.2)<<endl; }

     

    编译结果:

    warning C4244: “参数”: 从“double”转换到“int”,可能丢失数据

    三、非类型形参

    (1)模板的非类型形参

    模板的非类型形参也就是内置类型形参,如template<class T, int a> class B{};其中int a就是非类型的模板形参。

    (2)非类型形参在模板定义的内部是常量值,也就是说非类型形参在模板的内部是常量。

    (3)模板的非类型形参只能是整型,指针和引用

    double,String, String **这样的类型是不允许的。但是double &,double *,对象的引用或指针是正确的。

    (4)调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。

    (5)注意:任何局部对象,局部变量,局部对象的地址,局部变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能用作非类型模板形参的实参。

    (6) 全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参。

    (7)sizeof表达式的结果是一个常量表达式,也能用作非类型模板形参的实参。

    (8)当模板的形参是整型时调用该模板时的实参必须是整型的,且在编译期间是常量,比如template <class T, int a> class A{};如果有int b,这时A<int, b> m;将出错,因为b不是常量,如果const int b,这时A<int, b> m;就是正确的,因为这时b是常量。

    (9)非类型形参一般不应用于函数模板中,比如有函数模板template<class T, int a> void h(T b){},若使用h(2)调用会出现无法为非类型形参a推演出参数的错误,对这种模板函数可以用显示模板实参来解决,如用h<int, 3>(2)这样就把非类型形参a设置为整数3。显示模板实参在后面介绍。

    (10) 非类型模板形参的形参和实参间所允许的转换

    a、允许从数组到指针,从函数到指针的转换。如:template <int *a> class A{}; int b[1]; A<b> m;即数组到指针的转换

    b、const修饰符的转换。如:template<const int *a> class A{}; int b; A<&b> m; 即从int *到const int *的转换。

    c、提升转换。如:template<int a> class A{}; const short b=2; A<b> m; 即从short到int 的提升转换

    d、整值转换。如:template<unsigned int a> class A{}; A<3> m; 即从int 到unsigned int的转换。

    e、常规转换。

    实例:

    //由用户自己亲自指定栈的大小,并实现栈的相关操作
    //TemplateDemo.h
    
    #ifndef TEMPLATE_DEMO_HXX
    #define TEMPLATE_DEMO_HXX
    
    template<class T,int MAXSIZE> class Stack{//MAXSIZE由用户创建对象时自行设置 private: T elems[MAXSIZE]; // 包含元素的数组 int numElems; // 元素的当前总个数 public: Stack(); //构造函数 void push(T const&); //压入元素 void pop(); //弹出元素 T top() const; //返回栈顶元素 bool empty() const{ // 返回栈是否为空 return numElems == 0; } bool full() const{ // 返回栈是否已满 return numElems == MAXSIZE; } }; template <class T,int MAXSIZE> Stack<T,MAXSIZE>::Stack():numElems(0){ // 初始时栈不含元素 // 不做任何事情 } template <class T,int MAXSIZE> void Stack<T, MAXSIZE>::push(T const& elem){ if(numElems == MAXSIZE){ throw std::out_of_range("Stack<>::push(): stack is full"); } elems[numElems] = elem; // 附加元素 ++numElems; // 增加元素的个数 } template<class T,int MAXSIZE> void Stack<T,MAXSIZE>::pop(){ if (numElems <= 0) { throw std::out_of_range("Stack<>::pop(): empty stack"); } --numElems; // 减少元素的个数 } template <class T,int MAXSIZE> T Stack<T,MAXSIZE>::top()const{ if (numElems <= 0) { throw std::out_of_range("Stack<>::top(): empty stack"); } return elems[numElems-1]; // 返回最后一个元素 } #endif

     

    //TemplateDemo.cpp
    
    #include<iostream.h>
    #include <iostream>
    #include <string>
    #include <cstdlib> #include "TemplateDemo.h" int main(){ try { Stack<int,20> int20Stack; // 可以存储20个int元素的栈 Stack<int,40> int40Stack; // 可以存储40个int元素的栈 Stack<std::string,40> stringStack; // 可存储40个string元素的栈 // 使用可存储20个int元素的栈 int20Stack.push(7); std::cout << int20Stack.top() << std::endl; //7 int20Stack.pop(); // 使用可存储40个string的栈 stringStack.push("hello"); std::cout << stringStack.top() << std::endl; //hello stringStack.pop(); stringStack.pop(); //Exception: Stack<>::pop<>: empty stack return 0; } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; // 退出程序且有ERROR标记 } }

     

    参考资料

    [1] http://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html

     

    一、类模板的默认模板参数原则

      1、可以为类模板的类型形参提供默认值,但不能为函数模板的类型形参提供默认值。函数模板和类模板都可以为模板的非类型形参提供默认值。

      2、类模板的类型形参默认值形式为:

    template<class T1, class T2=int> class A{};

    为第二个模板类型形参T2提供int型的默认值。

      3、类模板类型形参默认值和函数的默认参数一样,如果有多个类型形参则从第一个形参设定了默认值之后的所有模板形参都要设定默认值,比如

    template<class T1=int, class T2>class A{};

    就是错误的,因为T1给出了默认值,而T2没有设定。

      4、在类模板的外部定义类中的成员时template 后的形参表应省略默认的形参类型。比如

    template<class  T1, class T2=int> class A{public: void h();}; 

    定义方法为

    template<class T1,class T2> void A<T1,T2>::h(){}

    二、验证上述原则

    //定义带默认类型形参的类模板。这里把T2默认设置为int型。
    template<class T1,class T2=int> class CeilDemo{ public: int ceil(T1,T2); }; //在类模板的外部定义类中的成员时template 后的形参表应省略默认的形参类型。 template<class T1,class T2> int CeilDemo<T1,T2>::ceil(T1 a,T2 b){ return a>>b; } int main(){ CeilDemo<int> cd; cout<<cd.ceil(8,2.5)<<endl; return 0; }

     

    输出2(8右移2位),另外会报一个double转int会丢失信息的warning。

    在类模板的外部定义类中的成员时template 后的形参表应省略默认的形参类型,如果没有省略,可能会依编译器不同有不同的处理方案(之前的vc可能只是报warning),我在vs2012和g++上是报错:

    error C4519: 仅允许在类模板上使用默认模板参数

    可见这里编译器将这里的默认参数认为是函数模板的。

    template<class T1=int,class T2=double,class T3=double> class CeilDemo{ public: double ceil(T1,T2,T3); }; template<class T1,class T2,class T3> double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } void main(){ CeilDemo<> cd; cout<<cd.ceil(2.5 ,3 ,4)<<endl; }

     

    输出9

    三、测试案例汇总

    //类模板非类型形参示例
    //模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
    //类模板的定义
    template<class T>class A{public:T g(T a, T b); A();}; //定义带有一个类模板类型形参T的类A template<class T1,class T2>class B{public:void g();}; //定义带有两个类模板类型形参T1,T2的类B //定义类模板的默认类型形参,默认类型形参不适合于函数模板。 template<class T1,class T2=int> class D{public: voidg();}; //定义带默认类型形参的类模板。这里把T2默认设置为int型。 //template<class T1=int, class T2>class E{}; //错误,为T1设了默认类型形参则T1后面的所有形参都必须设置认默值。 //以下为非类型形参的定义 //非类型形参只能是整型,指针和引用,像double,String, String **这样的类型是不允许的。但是double &,double *对象的引用或指 针是正确的。 template<class T1,int a> class Ci{public:void g();}; //定义模板的非类型形参,形参为整型 template<class T1,int &a>class Cip{public:void g();}; template<class T1,A<int>* m> class Cc{public:void g();}; //定义模板的模板类型形参,形参为int型的类A的对象的指针。 template<class T1,double*a>class Cd{public:void g();}; //定义模板的非类型形参,形参为double类型的引用。 class E{}; template<class T1,E &m> class Ce{}; //非类型模板形参为对象的引用。 //以下非类型形参的声明是错误的。 //template<class T1,A m>class Cc{}; //错误,对象不能做为非类型形参,非类型模板形参的类型只能是对象的引用或指针。 //template<class T1,double a>class Cc{}; //错误,非类型模板的形参不能是double类型,可以是double的引用。 //template<class T1,A<int> m>class Cc{}; //错误,非类型模板的形参不能是对象,必须是对象的引用或指针。这条规则对于模板型参 也不例外。 //在类模板外部定义各种类成员的方法, //typeid(变量名).name()的作用是提取变量名的类型,如int a,则cout<<typeid(a).name()将输出int template<class T> A<T>::A(){cout<<"class A goucao"<<typeid(T).name()<<endl;} //在类模板外部定义类的构造函数的方法 template<class T> T A<T>::g(T a,T b){cout<<"class A g(T a,T b)"<<endl;} //在类模板外部定义类模板的成员 template<class T1,class T2> voidB<T1,T2>::g(){cout<<"class g f()"<<typeid(T1).name()<<typeid(T2).name()<<endl;} //在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致 template<class T1,int a> voidCi<T1,a>::g(){cout<<"class Ci g()"<<typeid(T1).name()<<endl;} template<class T1,int &a> voidCip<T1,a>::g(){cout<<"class Cip g()"<<typeid(T1).name()<<endl;} //在类外部定义类的成员时,template后的模板形参应与要定义的类的模板形参一致 template<class T1,A<int> *m> voidCc<T1,m>::g(){cout<<"class Cc g()"<<typeid(T1).name()<<endl;} template<class T1,double* a> voidCd<T1,a>::g(){cout<<"class Cd g()"<<typeid(T1).name()<<endl;} //带有默认类型形参的模板类,在类的外部定义成员的方法。 //在类外部定义类的成员时,template的形参表中默认值应省略 template<class T1,class T2> voidD<T1,T2>::g(){cout<<"class D g()"<<endl;} //template<class T1,class T2=int> void D<T1,T2>::g(){cout<<"class D k()"<<endl;} //错误,在类模板外部定义带有默认类型的形 参时,在template的形参表中默认值应省略。 //定义一些全局变量。 int e=2; doubleed=2.2; double*pe=&ed; A<int> mw; A<int> *pec=&mw; E me; //main函数开始 int main() { // template<class T>void h(){} //错误,模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行。 //A<2> m; //错误,对类模板不存在实参推演问题,类模板必须在尖括号中明确指出其类型。 //类模板调用实例 A<int> ma; //输出"class A goucao int"创建int型的类模板A的对象ma。 B<int,int> mb; mb.g(); //输出"class B g() int int"创建类模板B的对象mb,并把类型形参T1和T2设计为int //非类型形参的调用 //调用非类型模板形参的实参必须是一个常量表达式,即他必须能在编译时计算出结果。任何局部对象,局部变量,局部对象的地址,局部 变量的地址都不是一个常量表达式,都不能用作非类型模板形参的实参。全局指针类型,全局变量,全局对象也不是一个常量表达式,不能 用作非类型模板形参的实参。 //全局变量的地址或引用,全局对象的地址或引用const类型变量是常量表达式,可以用作非类型模板形参的实参。 //调用整型int型非类型形参的方法为名为Ci,声明形式为template<class T1,int a> class Ci Ci<int,3>//正确,数值R是一个int型常量,输出"class Ci g() int" const int a2=3; Ci<int,a2> mci1; mci1.g(); //正确,因为a2在这里是const型的常量。输出"class Ci g() int" //Ci<int,a> mci; //错误,int型变量a是局部变量,不是一个常量表达式。 //Ci<int,e> mci; //错误,全局int型变量e也不是一个常量表达式。 //调用int&型非类型形参的方法类名为Cip,声明形式为template<class T1,int &a>class Cip Cip<int,e> mcip; //正确,对全局变量的引用或地址是常量表达式。 //Cip<int,a> mcip1; //错误,局部变量的引用或地址不是常量表达式。 //调用double*类型的非类形形参类名为Cd,声明形式为template<class T1,double *a>class Cd Cd<int,&ed> mcd; //正确,全局变量的引用或地址是常量表达式。 //Cd<int,pe> mcd1; //错误,全局变量指针不是常量表达式。 //double dd=3.3; //错误,局部变量的地址不是常量表达式,不能用作非类型形参的实参 //Cd<int,&e> mcd; //错误,非类型形参虽允许一些转换,但这个转换不能实现。 //调用模板类型形参对象A<int> *的方法类名为Cc,声名形式为template<class T1,A<int>* m> class Cc Cc<int,&mw> mcc; mcc.g(); //正确,全局对象的地址或者引用是常量表达式 //Cc<int,&ma> mcc; //错误,局部变量的地址或引用不是常量表达式。 //Cc<int,pec> mcc2; //错误,全局对象的指针不是常量表达式。 //调用非类型形参E&对象的引用的方法类名为Ce。声明形式为template<class T1,E &m> class Ce E me1; //Ce<int,me1> mce1; //错误,局部对象不是常量表达式 Ce<int,me> mce; //正确,全局对象的指针或引用是常量表达式。 //非类型形参的转换示例,类名为Ci //非类型形参允许从数组到指针,从函数到指针的转换,const修饰符的转换,提升转换,整值转换,常规转换。 const short s=3; Ci<int,s> mci4†//正确,虽然short型和int不完全匹配,但这里可以将short型转换为int型

     

    参考资料

    [1] http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html(注:此文有多处问题,请抱着谨慎态度查看)

    展开全文
  • 学习C++模板---模板类作为基类 使用模板类作为基类使用。 // 模板类-晋升.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <process.h> #include <...
  • 一、类模板定义及实例化 1. 定义一个模板: 1 templateclass 模板参数表> 2 3 class 类名{ 4 5 // 定义...... 6 7 };   其中,template 是声明模板的关键字,表示声明一个模板,模板...
  • “通常情况下,你会在.h文件中声明函数和,而将它们的定义放置在一个单独的.cpp...这就是什么所有的STL头文件都包含模板定义的原因。”[1] "标准要求编译器在实例化模板时必须在上下文中可以查看到其定义...
  • 1. 模板的概念。 我们已经学过重载(Overloading),对重载函数而言,C++的检查机制能通过函数参数的...例如,求两个数的最大值,我们定义MAX()函数需要对不同的数据类型分别定义不同重载(Overload)版本。 //函数1.
  • 模板使用总结 归纳以上的介绍,可以这样声明和使用模板: 先写出一个实际的。 将此类中准备改变的类型名(如int要改变float或char)改用一...用类模板定义对象时用以下形式: 模板名<实际类型名> 对
  • 类模板

    2018-10-24 15:55:13
    文章目录类模板1,类模板定义说明:2,类模板的实例化3,类模板参数(1)非类型参数(2)默认模板参数 1,类模板定义 类模板是公共逻辑的抽象,通常用来作为容器或者行为的封装。 一般定义格式: template&...
  • C++模板正确写法

    千次阅读 2018-04-08 16:42:26
    我们写模板传统的写法是这个样子的: 1. 把的整个框架写在 .h 文件中。//注意此文件中要写上 头文件保护符 2. 把中所有接口的实现写在 .cpp 中。 3. 在 main() 中创建 女朋友 ,调用女朋友的各种接口。...
  • 1. 模板的概念。...例如,求两个数的最大值,我们定义MAX()函数需要对不同的数据类型分别定义不同重载(Overload)版本。 //函数1. int max(int x,int y); {return(x>y)?x:y ;} //函数2. float
  • (1)在讲模板之前,先闲扯一下吧: C++最重要的特性之一就是代码重用,为了实现代码重用,代码必须具有通用性。 通用代码不受数据类型的影响,并且可以自动适应数据类型的变化,这种程序设计类型称为参数化程序设计...
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    内部的分类有哪些 静态内部 成员内部 局部内部 匿名内部 内部的优点 内部有哪些应用场景 局部内部和匿名内部访问局部变量的时候,什么变量必须要加上final? 内部相关,看程序说出运行结果 ...
  • (一)函数模板的概念 1--假设要编写一个函数对两个参数求和。实际编程中,我们可能希望定义几个这样的函数,每一个都可以对一种 给定类型的值求和,那么,可能自然会想到使用重载函数.例如: int add(int a,int b)...
  • C++函数模板模板函数)详解

    万次阅读 多人点赞 2019-07-04 16:03:01
    C++函数模板模板函数)详解定义用法:函数模板的原理延申用法2.1什么需要类模板2.2单个类模板语法2.3继承中的类模板语法案例1:案例2:2.4类模板的基础语法2.5类模板语法知识体系梳理1.所有的类模板函数写在的...
  • Java之自定义模板导出Word实例

    千次阅读 2017-05-14 21:50:34
    Java之自定义模板导出Word实例 本文利用Freemarker按照自定义模板.ftl文件生成相应的word文件,效果如下:   操作步骤: 首先下载jar包  新建一个word文档,注意:模板里面包含中文的话,一定记得改编...
  • C++模板学习和C++ 模板模板

    千次阅读 2014-08-04 16:08:37
    1. 模板的概念。...例如,求两个数的最大值,我们定义MAX()函数需要对不同的数据类型分别定义不同重载(Overload)版本。 //函数1. int max(int x,int y); {return(x>y)?x:y ;} //函数2. float
  • 模板及异常(小题)

    2020-06-27 17:07:31
    单选题: 2-1 现有声明: template class Test{...}; 则以下哪一个声明不可能正确。( A ) ...关于函数模板,描述错误的是。...A.函数模板必须由程序员实例化为可...一个类定义中,只要有一个函数模板,则这个类模板 D..
  • 一、类模板的默认模板参数原则 1、可以为类模板的类型形参提供默认值,但不能为函数模板的类型形参提供默认值。函数模板和类模板都可以为模板的非类型形参提供默认值。 2、类模板的类型形参默认值形式为:template...
  • 类模板最常见的链接错误

    千次阅读 2017-01-04 16:48:23
    大多数 C/C++ 程序员大致上都按照以下方式来组织他们的 non-template 程序代码:  Classes 和其它类型被全体放置于头文件(header files)。通常头文件的后缀名称(扩展名) .hpp(或 .H, .h, .hh, .hxx 等等)...
  • 函数模板参数

    千次阅读 2019-03-24 00:22:11
    C++模板实参的省略 下面列举的几种情况不能省略模板实参: 1)从模板函数实参表获得的信息有矛盾之处。 template<typename T> void fun(T const& a,T const& b);但是你调用时却是fun(250,250.4);那...
  • 1.有时对而言,两个或多个,其功能是相同的,仅仅是数据类型不同。 请看下面两个: class Compare_int{ public: Compare_int( int a, int b) {x = a; y = b;} int max(){return (x>y)? x : y;} int min...
  • c++模板类学习

    2019-02-21 10:53:15
    c++模板类学习
  • C++:模板总结

    万次阅读 多人点赞 2019-03-16 12:34:26
    写在前面 &nbsp;&nbsp;&nbsp;&nbsp;&...模板(Template)指C++程序设计设计...模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成...
  • C++ | 模板详解

    千次阅读 2019-03-10 00:31:37
    文章目录模板的基本概念概述什么是模板什么是函数模板什么是类模板模板的实例化模板的参数列表模板类型参数模板非类型参数模板的...模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 100,571
精华内容 40,228
关键字:

以下类模板定义正确的为