C++數(shù)據(jù)結(jié)構(gòu)模板進(jìn)階的多方面分析
??博客代碼已上傳至gitee:https://gitee.com/byte-binxin/cpp-class-code
??非類型模板參數(shù)
模板參數(shù)分類類型形參與非類型形參。
- 類型模板形參:出現(xiàn)在模板參數(shù)列表中,跟在class或者typename后面的參數(shù)類型名稱。(這個(gè)我們之前有講過(guò))
- 非類型模板形參:用一個(gè)常量作為模板的一個(gè)參數(shù),必須是整形家族中的類型參數(shù),否則不行。他在模板中可以當(dāng)常量使用。
實(shí)例:
// 類型模板參數(shù)
namespace wxj
{
// 非類型模板參數(shù) N 是一個(gè)常量參數(shù),只能是整形家族的:int short char long long long 自定義類型和其他類型都不能作費(fèi)類型模板參數(shù)
// 必須在編譯期就能確認(rèn)結(jié)果
template<class T, size_t N = 10>
class Array
{
public:
Array()
:_size(N)
{}
T& operator[](size_t i)
{
return _arr[i];
}
const T& operator[](size_t i) const
{
return _arr[i];
}
size_t size()
{
return _size;
}
bool empty()
{
return _size == 0;
}
private:
T _arr[N];
size_t _size;
};
void TestArray()
{
Array<int, 5> arr;
for (size_t i = 0; i < arr.size(); ++i)
{
arr[i] = i;
}
for (size_t i = 0; i < arr.size(); ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
}
int main()
{
wxj::TestArray();
return 0;
}
代碼運(yùn)行結(jié)果如下:

看上面,我們定義了一個(gè)數(shù)組類,空間大小由N決定,類型是Array<T, size_t>
注意:
- 非類型形參必須是整形家族中的類型,浮點(diǎn)數(shù)和類對(duì)象都不行。
- 非類型的模板形參必須在編譯期間就能確認(rèn)結(jié)果。
??模板的特化
模板特化:在原模板類的基礎(chǔ)上,針對(duì)特殊類型所進(jìn)行的特殊化的實(shí)現(xiàn)。分為函數(shù)模板特化 和類模板特化。
??函數(shù)模板的特化
特化的步驟
- 必須先有一個(gè)基礎(chǔ)的函數(shù)模板
- 關(guān)鍵字template后面接一對(duì)空的尖括號(hào)<>
- 函數(shù)名后跟一對(duì)尖括號(hào)<>,里面指定需要的特化的類型
- 函數(shù)形參列表:必須和函數(shù)模板的基礎(chǔ)參數(shù)類型完全一致
實(shí)例
// 模板的特化 模板的特殊化
template<class T>
bool IsEqual(T& left, T& right)
{
return left == right;
}
// 特化 針對(duì)某些類型進(jìn)行特殊化處理
template<>
bool IsEqual<const char* const>(const char* const& left, const char* const& right)
{
return strcmp(left, right) == 0;
}
注意: 一般情況下如果函數(shù)模板遇到不能處理或者處理有誤的類型,為了實(shí)現(xiàn)簡(jiǎn)單通常都是將該函數(shù)直接給出。
bool IsEqual(char* left, char* right)
{
return strcmp(left, right) == 0;
}
??類模板的特化
類模板的特化分為全特化和偏特化。
全特化: 對(duì)類模板參數(shù)列表的類型全部都確定(明確指定)
template <class T1, class T2>
class Date
{
public:
Date()
{
cout << "Date<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
// 全特化
template<>
class Date<int, double>
{
public:
Date()
{
cout << "Date<int, double>" << endl;
}
private:
int _d1;
double _d2;
};
偏特化: 堆類模板的參數(shù)列表中部分參數(shù)進(jìn)行確定化分為部分特化和參數(shù)進(jìn)一步限制
部分特化
// 部分
template<class T2>
class Date<int, T2>
{
public:
Date()
{
cout << "Date<int, T2>" << endl;
}
private:
int _d1;
T2 _d2;
};
參數(shù)進(jìn)一步限制 如下有T*和T&,是模板的類型轉(zhuǎn)為指針類型和引用類型
// 參數(shù)進(jìn)一步限制 堆模板參數(shù)更進(jìn)一步的條件限制
template <class T1, class T2>
class Date<T1*, T2&>
{
public:
Date(int& a)
:_d2(a)
{
cout << "Date<T1*, T2&>" << endl;
}
private:
T1* _d1;
T2& _d2;
};
實(shí)例 我們?cè)囍鴮?shí)例化幾個(gè)對(duì)象,看他們用的是哪個(gè)模板
int main()
{
Date<int, int> d1;
Date<int, double> d2;
Date<int, float> d3;
int a = 10;
Date<int*, int&> d4(a);
return 0;
}
代碼運(yùn)行結(jié)果:

??模板的分離編譯
分離編譯: 我們對(duì)這個(gè)應(yīng)該是不陌生的,就是把函數(shù)的聲明放在一個(gè)叫**.h的文件中,實(shí)現(xiàn)都放在一個(gè)叫.cpp**的文件中,這樣方便我們管理。
下面我們?cè)囍鴮?duì)模板進(jìn)行分離編譯:

// a.h
#pragma once
// 普通函數(shù)
void Swap(int& a, int& b);
// 函數(shù)模板
template<class T>
T Add(const T& a, const T& b);
// a.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "a.h"
// 普通函數(shù)
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
// 函數(shù)模板
template<class T>
T Add(const T& a, const T& b)
{
return a + b;
}
// test.cpp
#include "a.h"
int main()
{
int a = 3;
int b = 4;
Swap(a, b);
cout << "a = " << a << " b = " << b << endl;
cout << Add(a, b) << endl;
return 0;
}
代碼運(yùn)行結(jié)果如下

代碼運(yùn)行時(shí)發(fā)生了報(bào)錯(cuò),說(shuō)Add這個(gè)函數(shù)是沒(méi)有見過(guò)的。得出結(jié)論:函數(shù)模板不能分離編譯,普通函數(shù)可以。
為什么會(huì)這樣呢?
C++程序運(yùn)行一般經(jīng)過(guò)幾個(gè)階段:預(yù)處理——>編譯——>匯編——>鏈接(更詳細(xì)的內(nèi)容可以參考往期博客——程序的編譯)
- 模板在.cpp中定義了,由于不知道T的類型,所以沒(méi)有對(duì)模板進(jìn)行實(shí)例化。
- a.h 和 a.cpp 走的是兩條不同的路,兩條路都沒(méi)有對(duì)模板進(jìn)行實(shí)例化(因?yàn)椴恢繲的類型)。
- 因?yàn)闆](méi)有對(duì)模板進(jìn)行實(shí)例化,所以沒(méi)有函數(shù)參數(shù),也就沒(méi)有函數(shù)地址,所以在鏈接時(shí),test.cpp中的調(diào)用Add函數(shù)時(shí),沒(méi)有函數(shù)地址,call調(diào)用不到Add函數(shù),所以報(bào)錯(cuò)。
解決方法:
- 暴力:不分離編譯,統(tǒng)一放在一個(gè).h或.hpp的文件中
- 模板定義位置顯示實(shí)例化(不推薦,這樣就失去了泛型的特點(diǎn))
??總結(jié)
模板進(jìn)階也就是這些內(nèi)容了,喜歡的話,歡迎收藏支持~

到此這篇關(guān)于C++數(shù)據(jù)結(jié)構(gòu)模板進(jìn)階的多方面分析的文章就介紹到這了,更多相關(guān)C++ 模板進(jìn)階內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt利用QChart實(shí)現(xiàn)實(shí)時(shí)波形圖的繪制
這篇文章主要介紹了Qt如何利用QChart實(shí)現(xiàn)實(shí)時(shí)波形圖的繪制,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)有一定是參考價(jià)值,需要的可以參考一下2022-06-06
C++ 中滾動(dòng)條的滾動(dòng)問(wèn)題
本文主要通過(guò)一個(gè)示例,給大家介紹了C++中滾動(dòng)條的滾動(dòng)問(wèn)題,以及相關(guān)參數(shù)的解釋,非常的詳細(xì),有需要的小伙伴可以參考下。2015-06-06
C++進(jìn)程的創(chuàng)建和進(jìn)程ID標(biāo)識(shí)詳細(xì)介紹
傳統(tǒng)的C++(C++98)中并沒(méi)有引入線程這個(gè)概念。linux和unix操作系統(tǒng)的設(shè)計(jì)采用的是多進(jìn)程,進(jìn)程間的通信十分方便,同時(shí)進(jìn)程之間互相有著獨(dú)立的空間,不會(huì)污染其他進(jìn)程的數(shù)據(jù),天然的隔離性給程序的穩(wěn)定性帶來(lái)了很大的保障2022-08-08
DEV C++自動(dòng)補(bǔ)全文件頭的設(shè)置操作教程
Dev-C++ 是一款輕量級(jí)的集成開發(fā)環(huán)境 (IDE),主要用于 C 和 C++ 的程序編寫,它提供了基本的功能來(lái)幫助開發(fā)者更高效地工作,其中包括文件頭的自動(dòng)補(bǔ)全功能,本文就給大家介紹了DEV C++自動(dòng)補(bǔ)全文件頭的設(shè)置操作教程,需要的朋友可以參考下2025-04-04
C語(yǔ)言實(shí)現(xiàn)學(xué)生成績(jī)等級(jí)劃分的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于C語(yǔ)言實(shí)現(xiàn)學(xué)生成績(jī)等級(jí)劃分的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12

