类模板、变量模板、别名模板 基础知识点二

基本概念

  1. 类模板中的成员函数,只有源程序代码中出现调用这些成员函数的代码时,这些成员函数才会出现在一个实例化了的类模板中。
  2. 类模板中的成员函数模板,只有源程序中出现调用这些成员函数模板的代码时,这些成员函数的具体实例才会出现在一个实例化了的类模板中。
  3. 目前编译器并不支持虚成员函数模板:因为虚函数表vtbl的大小是固定的。C++之父说法:如果允许虚函数模板时,则每次有人用新的参数类型调用该虚函数时,就必须给对应的虚函数表再增加一项,这意味着只有链接程序才能去构造虚函数表,(在编译期间虚函数表vtbl就不能够固定),并在表中设置有关函数,因此,成员函数模板绝不能是虚的。
  4. 类模板中可以有普通的虚成员函数(虚函数),这并没有什么问题。大家都知道,普通成员函数如果不被调用的情况下,是不会被实例化出来的。但是,对于虚函数来说,不管是否调用,编译器都会把它实例化出来,因为编译器要创建虚函数表vtbl,该表中的每个具体表项都对应一个具体的虚函数地址,所以编译器必须的把所有的虚函数都实例化出来。
  5. 拷贝构造函数模板不是拷贝构造函数,拷贝赋值运算符模板不是拷贝赋值运算符函数,同时拷贝构造函数模板也不是拷贝构造函数。因为拷贝构造函数或者拷贝赋值运算符要求拷贝的对象类型完全相同,而拷贝构造函数和拷贝赋值运算符模板没有这种要求。
  6. 拷贝构造模板绝对永远不可能成为拷贝构造函数。编译器不会用调用拷贝构造函数模板来代替调用拷贝构造函数。
  7. 拷贝构造函数模板什么时候调用?类型不同(都是用类模板A实例化出来的,例如:A,A) 的两个对象,用一个拷贝另外一个时候。
  8. 拷贝赋值运算符模板 永远不可能成为拷贝赋值运算符函数,调用行为和拷贝构造函数模板行为是一样的。

成员函数模板特化

  1. 成员函数模板特化,不同的编译器支持程度不一样。
  2. 类模板中成员函数全特化还不太完善,写代码时需要注意测试。
  3. 实际工作中,建议把这些特化版本写在模板内部,然后类模板写在头文件中。

类模板中的类模板(嵌套)

  1. 根据类作用域符号 :: 来界定。

变量模板与成员变量模板

变量模板的特化(Variable templates)

  1. C++14 新标准中引入的。(一般放在 .h头文件中)
  2. 三种零初始化方式。a) int temp=int() b) int temp2={} c) int temp3 = int{}
#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp1
{
   template <typename T>
   T g_myvar{}; //等级于 T g_myvar=0,该写法 一般只适合数值类型
                //{}是对变量的初始化方式,叫做零初始化方式。int=0,指针=nullptr,bool=false
}

int main(int argc,char* argv[])
{
	_nmsp1::g_myvar<float> = 15.6f;
    _nmsp1::g_myvar<int> = 13;

    cout<<_nmsp1::g_myvar<float> <<endl;
    cout<<_nmsp1::g_myvar<int> <<endl;

	return 0;
}
  1. 变量模板的全特化。变量模板全特化的时候,并不需要正在特化的类型(double) 与 这个变量模板的类型(char) 保持一致。
#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp1
{
   //g_myvar的泛化版本
   template <typename T>
   T g_myvar{}; //等级于 T g_myvar=0,该写法 一般只适合数值类型
                //{}是对变量的初始化方式,叫做零初始化方式。int=0,指针=nullptr,bool=false

   template<>
   char g_myvar<double>{};
}

int main(int argc,char* argv[])
{
	_nmsp1::g_myvar<double> = '2'; //使用全特化版本的g_myvar变量模板
    cout<<_nmsp1::g_myvar<double> <<endl;
    printf("%d\n",_nmsp1::g_myvar<double>);
    printf("%c\n",_nmsp1::g_myvar<double>);

	return 0;
}
  1. 变量模板的偏特化。
#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp1
{
   //g_myvar的泛化版本
   template <typename T>
   T g_myvar{}; //等级于 T g_myvar=0,该写法 一般只适合数值类型
                //{}是对变量的初始化方式,叫做零初始化方式。int=0,指针=nullptr,bool=false
   //全特化
   template<>
   char g_myvar<double>{};

   //偏特化
   template <typename T>
   T g_myvar<T*> {120};  //要求T* 必须依赖与 T
   //T g_myvar<double*> {120}; compile error!
}

int main(int argc,char* argv[])
{
	_nmsp1::g_myvar<double> = '2'; //使用全特化版本的g_myvar变量模板
    cout<<_nmsp1::g_myvar<double> <<endl;
    printf("%d\n",_nmsp1::g_myvar<double>);
    printf("%c\n",_nmsp1::g_myvar<double>);

    //偏特化
    cout<<_nmsp1::g_myvar<int*> <<endl; //120
    //g_myvar的泛化版本
    cout<<_nmsp1::g_myvar<int> <<endl;  //0

	return 0;
}

默认模板参数

#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp2
{
   //g_myvar的泛化版本
   template <typename T=int>
   T g_myvar{}; //等级于 T g_myvar=0,该写法 一般只适合数值类型
                //{}是对变量的初始化方式,叫做零初始化方式。int=0,指针=nullptr,bool=false
}

int main(int argc,char* argv[])
{
	
    _nmsp2::g_myvar<int> = 13;
    
    cout<<_nmsp2::g_myvar<> <<endl;

    _nmsp2::g_myvar<> = 26; //等价于 _nmsp2::g_myvar<int>

    cout<<_nmsp2::g_myvar<> <<endl;

	return 0;
}

非类型模板参数

#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp3
{
   //g_myvar的泛化版本
   template <typename T,int value>
   T g_myvar[value]; //等级于 T g_myvar=0,该写法 一般只适合数值类型
                //{}是对变量的初始化方式,叫做零初始化方式。int=0,指针=nullptr,bool=false
}

int main(int argc,char* argv[])
{
    for(size_t i=0;i<15;i++)
    {
        _nmsp3::g_myvar<int,15>[i] = i+1;
    }

    for(size_t i=0;i<15;i++)
    {
        cout<<_nmsp3::g_myvar<int,15>[i] <<endl;
    }

	return 0;
}

变量模板的另一种形式

#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp4
{
    template <typename T>
    struct B
    {
        public:
            const static T value = {160}; //const 也可以写成 constexpr,{}也可以不加
    };
    template <typename T>
    int g_myvar4 = B<T>::value; //注意 g_myvar4 是个变量模板
}

int main(int argc,char* argv[])
{
    cout<< _nmsp4::g_myvar4<int> <<endl;

    _nmsp4::g_myvar4<int> =152;

    cout<< _nmsp4::g_myvar4<int> <<endl;

    cout<<_nmsp4::B<int>::value <<endl;

	return 0;
}

成员变量模板

#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp5
{
    template <typename T>
    class Demo
    {
        public:
            template<typename W>
            static W m_tpi; // 静态成员变量模板声明
    };

    template <typename T>
    template<typename W>
    W Demo<T>::m_tpi = 5; //定义
}

int main(int argc,char* argv[])
{
    
    cout<<_nmsp5::Demo<float>::m_tpi<int> <<endl;
    _nmsp5::Demo<float>::m_tpi<int> = 150;
    cout<<_nmsp5::Demo<float>::m_tpi<int> <<endl;

	return 0;
}

别名模板与成员别名模板

  1. 别名模板(Alias Templates),C++11 新标准引入的,引入的目的不但可以简化书写,而且可以达到一些通过其他手段难以达到的目的。
#include <iostream>
#include <list>
#include <map>
#include <string>

using namespace std;

namespace _nmsp6
{
    //别名模板
    template <typename T>
    using str_map_t = std::map<std::string, T>;

    template <typename W>
    class E
    {
        //成员别名模板
    private:
        template <typename W>
        using str_map_t = std::map<std::string, W>;

    public:
        str_map_t<int> map1;
    };
}

int main(int argc, char* argv[])
{

    _nmsp6::str_map_t<int> map1;
    map1.insert({ "first",1 });
    map1.insert(make_pair("second", 2));

    for (auto iter = map1.begin(); iter != map1.end(); iter++)
    {
        cout << iter->first << "," << iter->second << endl;
    }
    cout << endl;

    _nmsp6::E<float> obja;
    obja.map1.insert({"three",3});
    obja.map1.insert(make_pair("four",4));

    for (auto iter = obja.map1.begin(); iter != obja.map1.end(); iter++)
    {
        cout << iter->first << "," << iter->second << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

repinkply

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值