【c++】模板编程解密:C++中的特化、实例化和分离编译

慈云数据 2024-05-14 技术支持 48 0

Alt

🔥个人主页:Quitecoder

🔥专栏:c++笔记仓

Alt

朋友们大家好,本篇文章我们来学习模版的进阶部分

目录

  • `1.非类型模版参数`
    • `按需实例化`
    • `2.模版的特化`
      • `函数模版特化`
      • `函数模版的特化`
      • `类模版`
        • `全特化`
        • `偏特化`
        • `3.分离编译`
          • `模版分离编译`

            1.非类型模版参数

            模板参数分类类型形参与非类型形参。

            • 类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称
            • 非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用

              非类型模板参数允许你将一个值(而不是一个类型)直接传递给一个模板。非类型模板参数可以是一个整型值、一个指针或者一个引用,因为这些参数不是类型,所以被称为“非类型模板参数”。

              非类型模板参数可以让你根据这些值创建模板实例。例如,你可以根据整型非类型模板参数定义编译时决定大小数组

              引入下面的例子:

              #define N 10
              template
              class array
              {
              public:
              	T& operator[](size_t index) { return _array[index]; }
              	const T& operator[](size_t index)const { return _array[index]; }
              	size_t size()const { return _size; }
              	bool empty()const { return 0 == _size; }
              private:
              	T _array[N];
              	size_t _size;
              };
              

              对于这个静态数组,我们只能用宏定义来确定数组的大小,那如果我一次性想要开两个大小不同的数组呢?

              array a1;//大小为10
              array a2;//大小为100
              

              这里就需要非类型模版参数

              template
              class array
              {
              public:
              	T& operator[](size_t index) { return _array[index]; }
              	const T& operator[](size_t index)const { return _array[index]; }
              	size_t size()const { return _size; }
              	bool empty()const { return 0 == _size; }
              private:
              	T _array[N];
              	size_t _size;
              };
              

              在这个例子中,N 就是一个非类型模板参数,它表示数组的大小,而 T 是一个类型模板参数代表数组中元素的类型

              使用方法

              array a1;
              array a2;
              

              注意:

              • 浮点数、类对象以及字符串是不允许作为非类型模板参数的
              • 使用非类型模板参数的时候,你传递的值必须在编译时就确定下来。这意味着你不能用动态计算的值或者运行时才能得知的值作为非类型模板参数的实参

                按需实例化

                按需实例化,是 C++ 模板的一个重要特性,指的是模板代码只有在真正被使用时才会被编译器实例化

                在 C++ 中,模板本身并不直接生成可执行代码;它们是用于生成代码的蓝图。当你编写一个模板类或模板函数时,你实际上是在告诉编译器如何在需要的时候用具体的类型或值生成代码。这种生成过程只有在模板被用到的时候才会发生,换言之,只有在代码中显式或隐式地引用了模板的具体实例,编译器才会根据模板生成那个特定实例的代码。这就是所谓的按需实例化

                比如,对于上面的代码,我在T& operator[]函数中写一个错误的语法

                T& operator[](size_t index) 
                	{
                		size(1);
                		return _array[index]; 
                	}
                

                并没有产生编译错误

                由于模板的这个行为,如果模板的某些部分(在本例中是 _size的使用)没有在代码中被实际使用,那么编译器可能不会去实例化或者编译这个部分,它可能不会产生编译错误

                在一些编译器和编译设置下,成员函数模板只有在被调用时才会实例化。如果编译器没有看到 size() 或者 empty()的任何调用,它也就不会去检查 _size 是否已经初始化,就不会产生潜在的错误

                此外,对于 operator[] 的实现:

                T& operator[](size_t index)
                {
                    size(1); // 这里的调用看上去像是一个函数调用,但是没有意义,因为它对程序行为没有任何影响。
                    return _array[index];
                }
                

                size(1); 这行代码试图调用 size() 成员函数并传递一个参数,但这显然是不正确的,因为 size() 没有定义接受参数的版本,应该是 size_t size()const。如果在代码中有地方调用了这个重载的 operator[],并且编译器实例化了这部分代码,则会产生编译错误。但如果没有任何地方使用了这个重载的 operator[],编译器则不会去检查这部分代码,错误也就没有暴露出来

                2.模版的特化

                函数模版特化

                通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

                template
                bool Less(T left, T right)
                {
                	return left 
微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon