C++模板(下)

本文详细介绍了C++中的模板,包括非类型模板参数的使用、模板的特化方法,以及模板分离编译的问题和解决方案。同时讨论了模板的优缺点,如代码复用、代码膨胀和编译挑战。
摘要由CSDN通过智能技术生成

【C++修炼秘籍】模板(下)

🌸心有所向,日复一日,必有精进

🌸专栏《C++修炼秘籍》

🌸作者:早凉


目录

【C++修炼秘籍】模板(下)

文章目录

前言

一、非类型的模板参数

二、模板的特化

三、模板分离编译

总结


前言

泛型编程的有力支撑——模板,在上次的文章中已经可以使用起来,也对STL的学习有了很大作用,本文会再次将一些细小知识汇总作为参考。


一、非类型的模板参数

类型模板,T是类型,在下方的场景中,如果我们想在类中开辟数组,如果通过宏,我们就必须修改宏; 

template<class T>//是类型模板
#define N 10
class Array
{
    private:
       T a;
       T a[N]; 
}
int main()

{
    Array<int> a1;
    Array<double>a2;
}

 N是一个非类型的模板参数,用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

template<class T ,size_t N = 10>//后后边就是非类型怒版参数
{
    private:
        T _arry;
        T _a[N];
}
int main()

{
	array<int,10>a2;
    int a3[10];
}

 在库里,C++11中支持的一个静态数组,这里就是实现非类型的模板参数。

  ❓但是C语言就有静态数组支持啊?为什么库里还要在C++11里还要实现什么?

 诶,我们发现我们这不是越界访问了吗?问什么编译器没报错啊,这是很危险的啊,

 这时我们发现,array是强制检查的。

原生数组对于越界的检查:越界读不检查;越界写会抽查

array对于越界的检查::array只要越界就检查,比起原生数组更加严格;

 ❗️ 注意

1、浮点数、类对象,以及字符串是不允许作为非类型的模板参数的;

2、非类型的模板参数必须在编译器就能确认结果;

二、模板的特化

函数模板

针对某些类型进行特殊处理例如:日期类

template<class T>
    bool Less(T left,T right)
{
    return left<right;
}
//是上面那个特殊处理针对Date的特化
template<>
bool Less<Date*>(Date*left,Date*right)
{
    return *left<*right;
}
//构成重载也是可以
bool Less(Date*left,Date*right)
{
    return *left<*right;
}
Date d1();
Date d1();
cout<<Less(d1,d2)<<endl;
Date* p1 = &d1;
Date* p2 = &d2;
cout<<Less(p1,p2)<<endl;

类模板

类模板就不能写个函数了,只能特化;

    template<class T,class N>
    class D{
        public:
            D(){
                cout<<"T,N"<<endl;
            }
        private:
        	T t;
        	N n;
    }
//特化全特化
    template<>
    class D<double,double>{
        public:
            D(){
                cout<<"double,double"<<endl;
               }
        private:
    }

半特化/偏特化  

    template<class T>
    class D<T,char>{
        public:
            D(){
                cout<<"T,char"<<endl;
               }
        private:
    }

参数类型进一步限制 (也属于半特化) 

template<class T,class N>
class D<T*,N*>
{
public:
	D(){cout<<"T*,N*"<<endl;}
}
template<class T,class N>
class D<T&,N&>
{
public:
	D(){cout<<"T&,N&"<<endl;}
}

 ❗️  体现匹配原则:有全特化就优先全特化,其次半特化,最后模板;

三、模板分离编译

声明和定义分离是有大问题的 :

//template.h
#pragma once
template<class T>
T Add(const T& left, const T& right);
///template.h///
#include"template.h"
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
///test.h//
#include<iostream>
using namespace std;
#include"template.h"
int main()
{
	Add(11, 22);
	Add(3.2, 2.1);
	return 0;
}

 

发现这里我们找不到Add函数呀,这是因为 在add.cpp中在没有传参的时候不会对Add模板实例化,因此不会产生具体的函数,在main.obj中调用Add<int>在编译器链接是才会找地址,但是这俩函数没有实例化成具体代码,因此链接报错。

  如何解决?

1、将声明和定义放到一个文件 ;
2、模板定义的位置显式实例化;;

template int Add<int>(const int&, const int&);
template double Add<double>(const double&, const double&);

上述是函数模板,那么类模板该怎么办呢?

 

/.h/
#pragma once
template <class T>
class CSwap{
public:
	CSwap(T a, T b);
	void Swap();
public:
	T _a;
	T _b;
};
/CSwap.cpp///
#include"template.h"
template <class T>
void CSwap<T>::Swap()
{
	T tmp = _a;
	_a = _b;
	_b = tmp;
}
template <class T>
CSwap<T>::CSwap(T a, T b)
{
	_a = a; _b = b;
}
///test.cpp/
#include<iostream>
using namespace std;
#include"template.h"
int main()
{

	CSwap<int> c(1,2);
	c.Swap();
	cout << c._a << " " << c._b << endl;
}

 

看着熟悉的报错!那么类模板怎么解决呢?——在CSwap.cpp文件中加入:

template
class CSwap<int>;


总结

模板的缺点

分离编译,链接之前不会交互,没有实例化;模板的报错特别**,就是会给人打电报的感觉,摸不到头脑;模板会导致代码膨胀问题,也会导致编译时间变长

优点:

模板复用了代码,节省资源,更快的迭代开发,产生了C++的标准模板库(STL)
增强了代码的灵活性


如果觉得有帮助的话,可以点赞 + 收藏 + 评论支持一下哦!这对我的帮助很大~:)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值