亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++11中模板隱式實例化與顯式實例化的定義詳解分析

 更新時間:2022年04月25日 08:38:59   作者:云飛揚_Dylan  
實例化是為在程序中的函數(shù)模板本身并不會生成函數(shù)定義,它只是一個用于生成函數(shù)定義的方案。編譯器使用模板為特定類型生成函數(shù)定義時,得到的是模板實例。這即是函數(shù)模板的實例化。而函數(shù)模板實例化又分為兩種類型:隱式實例化和顯式實例化

1. 隱式實例化

在代碼中實際使用模板類構(gòu)造對象或者調(diào)用模板函數(shù)時,編譯器會根據(jù)調(diào)用者傳給模板的實參進(jìn)行模板類型推導(dǎo)然后對模板進(jìn)行實例化,此過程中的實例化即是隱式實例化。

template<typename T>
T add(T t1, T2)
{
    return t1 + t2;
}
template<typename T>
class Dylan
{
public:
    T m_data;
};
int main()
{
    int ret = add(3,4);//隱式實例化,int add<int>(int t1, int t2);
    Dylan<double> dylan;//隱式實例化
}

2. 顯式實例化聲明與定義

extern template int add<int>(int t1, int t2);//顯式實例化聲明
extern template class Dylan<int>;            //顯式實例化聲明
template int add<int>(int t1, int t2);       //顯式實例化定義
template class Dylan<int>;                   //顯式實例化定義

當(dāng)編譯器遇到顯式實例化聲明時,表示實例化定義在程序的其他地方(相對于當(dāng)前cpp文件)即在其他某一個cpp文件中定義,因此不再按照模板進(jìn)行類型推導(dǎo)去生成隱式實例化定義。

當(dāng)編譯器遇到顯式實例化定義時,根據(jù)定義所提供的模板實參去實例化模板,生成針對該模板實參的實例化定義。

3. 顯式實例化的用途

模板類、函數(shù)通常定義在頭文件中,這些頭文件會被很多cpp文件包含,在這些cpp文件中會多次使用這些模板,比如下面的例子:

//template.hpp
template<typename T>
class Dylan
{
public:
    T m_data;
};
//test1.cpp
#include "template.hpp"
Dylan<int> t1;
Dylan<int> t2;
//test2.cpp
#include "template.hpp"
Dylan<int> t3;
Dylan<int> t4;

在test1.cpp/test2.cpp 中多次實例化了Dylan<int>類,按說編譯完后的可執(zhí)行程序中會包含多份Dylan<T>的定義,然而實際上,整個程序中卻只有一份Dylan<T>的定義。這個處理是在編譯和鏈接過程中實現(xiàn)的,目前主流的實現(xiàn)模式有兩種:      

a. Borland模式

Borland模式通過在編譯器中加入與公共塊等效的代碼來解決模板實例化問題。在編譯時,每個文件獨立編譯,遇到模板或者模板的實例化都不加選擇地直接編譯。在鏈接的時候?qū)⑺心繕?biāo)文件中的模板定義和實例化都收集起來,根據(jù)需要只保留一個。這種方法實現(xiàn)簡單,但因為模板代碼被重復(fù)編譯,增加了編譯時間。在這種模式下,我們編寫代碼應(yīng)該盡量讓模板的所有定義都放入頭文件中,以確保模板能夠被順利地實例化。要支持此模式,編譯器廠商必須更換支持此模式的鏈接器。

b. Cfront模式

AT&T編譯器支持此模式,每個文件編譯時,如果遇到模板定義和實例化都不直接編譯,而是將其存儲在模板存儲庫中(template repository)。模板存儲庫是一個自動維護(hù)的存儲模板實例的地方。在鏈接時,鏈接器再根據(jù)實際需要編譯出模板的實例化代碼。這種方法效率高,但實現(xiàn)復(fù)雜。在這種模式下,我們應(yīng)該盡量將非內(nèi)聯(lián)成員模板的定義分離到一個單獨的文件中,進(jìn)行單獨編譯。

在一個鏈接器支持Borland模式的編譯目標(biāo)(編譯后的可執(zhí)行文件)上,g++使用Borland模式解決實例化問題。比如ELF(Linux/GNU), Mac OS X, Microsoft windows, 否則,g++不支持上述兩種模式。

如何避免Borland模式的缺點?

上面我們說g++實現(xiàn)的是Borland 模式,由于我們?yōu)槊恳环輰嵗纱a,這樣在大型程序中就有可能包含很多重復(fù)的實例化定義代碼,雖然鏈接階段,鏈接器會剔除這些重復(fù)的定義,但仍然會導(dǎo)致編譯過程中的目標(biāo)文件(或者共享庫文件)過于龐大。這時候,我們就可以通過C++11的模板顯式實例化的方法解決??聪旅娴拇a:

// template.hpp
template<typename T>
class Dylan
{
public:
    Dylan(T t);
    T m_data;
};
// template.cpp
#include "template.hpp"
template<typename T>
Dylan<T>::Dylan(T t)
{
    m_data = t;
}
template class Dylan<int>; //模板實例化定義
// main.cpp
#include "template.hpp"
extern template class Dylan<int>; //模板實例化聲明,告訴編譯器,此實例化在其他文件中定義
                                  //不需要根據(jù)模板定義生成實例化代碼  
int main()
{
    Dylan<int> dylan(3);//OK, 使用在template.cpp中的定義
    Dylan<float> dylan1(3.0);//error, 引發(fā)未定義錯誤
}

   上面的代碼中,我們將模板類的具體定義放在template.cpp中,并且在template.cpp中通過顯式實例化定義語句具體化了Dylan<int>。在main.cpp中,我們通過顯式實例化聲明告訴編譯器,Dylan<int>將在其他文件中定義,不需要在本文件中根據(jù)template.hpp的類模板實例化Dylan<int>。

由于我們沒有針對Dylan<float>做顯式實例化的聲明和定義,因此Dylan<float> dylan(3.0)會根據(jù)template.hpp中的類模板定義進(jìn)行隱式實例化,然而構(gòu)造函數(shù)是在template.cpp文件中定義的,在template.hpp中找不到構(gòu)造函數(shù)的定義,因而報錯。如果把構(gòu)造函數(shù)的定義挪回template.hpp,那Dylan<float>就能通過編譯了。

Note:在編譯中,如果指定-fno-implicit-templates,編譯器就會禁止隱式實例化,從而只使用顯式實例化。

參考文獻(xiàn):Template Instantiation (Using the GNU Compiler Collection (GCC))

到此這篇關(guān)于C++11中模板隱式實例化與顯式實例化的定義詳解分析的文章就介紹到這了,更多相關(guān)C++模板實例化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用VS Code進(jìn)行Qt開發(fā)的實現(xiàn)

    使用VS Code進(jìn)行Qt開發(fā)的實現(xiàn)

    這篇文章主要介紹了使用VS Code進(jìn)行Qt開發(fā)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • c++中string類型和int類型相互轉(zhuǎn)換的幾種常用方法

    c++中string類型和int類型相互轉(zhuǎn)換的幾種常用方法

    我們在編寫程序時,經(jīng)常涉及到int與string之間的類型轉(zhuǎn)換,本文主要介紹了c++中string類型和int類型相互轉(zhuǎn)換的幾種常用方法,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08
  • C++中NULL與nullptr的區(qū)別對比

    C++中NULL與nullptr的區(qū)別對比

    nullptr是c++11中的關(guān)鍵字,下面這篇文章主要介紹了C++中NULL與nullptr區(qū)別的相關(guān)資料,對大家來說還是挺實用的,需要的朋友可以參考下
    2021-05-05
  • C++實現(xiàn)簡單通訊錄系統(tǒng)

    C++實現(xiàn)簡單通訊錄系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)簡單通訊錄系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Qt處理焦點事件(獲得焦點,失去焦點)

    Qt處理焦點事件(獲得焦點,失去焦點)

    本文主要介紹了Qt處理焦點事件(獲得焦點,失去焦點),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-12-12
  • C語言零基礎(chǔ)講解指針和數(shù)組

    C語言零基礎(chǔ)講解指針和數(shù)組

    由于數(shù)據(jù)的表現(xiàn)形式多種多樣,還有字符型和其它的數(shù)值類型,因此僅有基本數(shù)據(jù)類型是不夠的。是否可以通過基本數(shù)據(jù)類型的組合抽象構(gòu)造其它的數(shù)據(jù)類型呢?下面是小編為大家?guī)淼腃語言數(shù)組與指針詳解的知識
    2022-04-04
  • 基于C語言實現(xiàn)計算生辰八字五行的示例詳解

    基于C語言實現(xiàn)計算生辰八字五行的示例詳解

    生辰八字,簡稱八字,是指一個人出生時的干支歷日期;年月日時共四柱干支,每柱兩字,合共八個字。這篇文章主要介紹了C語言實現(xiàn)計算生辰八字五行的示例代碼,需要的可以參考一下
    2023-03-03
  • 聊聊C++中右值引用和移動構(gòu)造函數(shù)的使用

    聊聊C++中右值引用和移動構(gòu)造函數(shù)的使用

    這篇文章主要是來和大家一起聊聊C++中右值引用和移動構(gòu)造函數(shù)的使用,文中通過示例進(jìn)行了詳細(xì)講解,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-07-07
  • c++11新增的便利算法實例分析

    c++11新增的便利算法實例分析

    這篇文章主要介紹了c++11新增的便利算法,主要有用于判斷、查找、數(shù)組、序列等的操作算法,非常具有實用價值,需要的朋友可以參考下
    2014-09-09
  • 利用C語言解決八皇后問題以及解析

    利用C語言解決八皇后問題以及解析

    這篇文章主要給大家介紹了關(guān)于利用C語言解決八皇后問題以及解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12

最新評論