最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C++模板——函數(shù)模板

2022-11-16 12:40 作者:限量版范兒  | 我要投稿

1.1 定義函數(shù)模板

  • template<typename T>

  • T max(T a,T b) {

  • return b < a ? a : b;

  • }

1.2 使用函數(shù)模板

  • std::cout << max(7,42) << std::endl;


  • std::cout << max(1.1,2.2) << std::endl;


  • std::cout << max("math","mathematics") << std::endl;

模板不是被編譯成可以處理任何類型的單個(gè)函數(shù)。相反,編譯器會(huì)針對(duì)每一個(gè)使用該模板的類型生成對(duì)應(yīng)的函數(shù)。例如,max(7,42)的調(diào)用在語(yǔ)義上相當(dāng)于調(diào)用了:

  • int max(int a,int b) {

  • return b < a ? a : b;

  • }

double、string同理。

將模板參數(shù)替換成具體參數(shù)類型的過(guò)程叫做instantiation,這個(gè)過(guò)程會(huì)產(chǎn)生一個(gè)instance of template。

1.3 兩階段翻譯 Two-Phase Translation

如果某一特定參數(shù)類型不支持模板內(nèi)的操作,那么編譯階段會(huì)報(bào)錯(cuò),例如:

  • std::complex<float> c1,c2; ? ? ? ?//不支持 max中的 < 操作,編譯階段會(huì)報(bào)錯(cuò)

  • ...

  • max(c1,c2);

模板會(huì)分成兩個(gè)階段進(jìn)行”編譯“:

  1. 在不進(jìn)行模板instantiationdefinition time階段,此時(shí)會(huì)忽略模板參數(shù),檢查如下方面:

    • 語(yǔ)法錯(cuò)誤,包括缺失分號(hào)。

    • 使用未定義參數(shù)。

    • 如果static assertion不依賴模板參數(shù),會(huì)檢查是否通過(guò)static assertion.

  2. instantiation階段,會(huì)再次檢查模板里所有代碼的正確性,尤其是那些依賴模板參數(shù)的部分。

例如:

  • template<typename T>

  • void foo(T t) {

  • undeclared(); ? ? ? ? // first-phase compile-time error if undeclared() unknown


  • undeclared(t); ? ? ? // second-phase compile-time error if undeclared(T) unknown


  • static_assert(sizeof(int) > 10,"int too small"); ? ? ?// first-phase compile-time error


  • static_assert(sizeof(T) > 10, "T too small"); ? ? ? ?// second-phase compile-time error


  • }

1.3.1 模板的編譯和鏈接問(wèn)題

大多數(shù)人會(huì)按照如下方式組織非模板代碼:

  • 將類或者其他類型聲明放在頭文件(.hpp、.H、.h、.hh、.hxx)中。

  • 將函數(shù)定義等放到一個(gè)單獨(dú)的編譯單元文件中(.cpp、.C、.c、.cc、.cxx)。

但是這種組織方式在包含模板的代碼中卻行不通,例如:
頭文件:

  • // myfirst.hpp

  • #ifndef MYFIRST_HPP

  • #define MYFIRST_HPP

  • // declaration of template

  • template<typename T>

  • void printTypeof (T const&);

  • #endif // MYFIRST_HPP

定義函數(shù)模板的文件:

  • // myfirst.cpp

  • #include <iostream>

  • #include <typeinfo>

  • #include "myfirst.hpp"

  • // implementation/definition of template

  • template<typename T>

  • void printTypeof (T const& x) {

  • std::cout << typeid(x).name() << '\n';

  • }

在另一個(gè)文件中使用該模板:

  • // myfirstmain.cpp

  • #include "myfirst.hpp"

  • // use of the template

  • int main() {

  • double ice = 3.0;

  • printTypeof(ice); // call function template for type double

  • }

在c/c++中,當(dāng)編譯階段發(fā)現(xiàn)一個(gè)符號(hào)(printTypeof)沒(méi)有定義只有聲明時(shí),編譯器會(huì)假設(shè)它的定義在其他文件中,所以編譯器會(huì)留一個(gè)”坑“給鏈接器linker,讓它去填充真正的符號(hào)地址。

但是上面說(shuō)過(guò),模板是比較特殊的,需要在編譯階段進(jìn)行instantiation,即需要進(jìn)行模板參數(shù)類型推斷,實(shí)例化模板,當(dāng)然也就需要知道函數(shù)的定義。但是由于上面兩個(gè)cpp文件都是單獨(dú)的編譯單元文件,所以當(dāng)編譯器編譯myfirstmain.cpp時(shí),它沒(méi)有找到模板的定義,自然也就沒(méi)有instantiation。

解決辦法就是我們把模板的聲明和定義都放在一個(gè)頭文件。大家可以看一下自己環(huán)境下的vector等STL源文件,就是把類的聲明和定義都放在了一個(gè)文件中。

1.4 多模板參數(shù)

  • template<typename T1, typename T2>

  • T1 max (T1 a, T2 b) {

  • return b < a ? a : b;

  • }

  • ...

  • auto m = max(4, 7.2); ? ? ? // 注意:返回類型是第一個(gè)模板參數(shù)T1 的類型

但是問(wèn)題正如注釋中說(shuō)的,max的返回值類型總是T1。如果我們調(diào)用max(42, 66.66),返回值則是66。

一般有三個(gè)方法解決這個(gè)問(wèn)題:

  • 引入額外模板參數(shù)作為返回值類型

  • 讓編譯器自己找出返回值類型

  • 將返回值聲明為兩個(gè)模板參數(shù)的公共類型,比如int和float,公共類型就是float

1.4.1 引入額外模板參數(shù)作為返回值類型

在函數(shù)模板的參數(shù)類型推導(dǎo)過(guò)程中,一般我們不用顯式指定模板參數(shù)類型。但是當(dāng)模板參數(shù)不能根據(jù)傳遞的參數(shù)推導(dǎo)出來(lái)時(shí),我們就需要顯式的指定模板參數(shù)類型。

  • template<typename T1, typename T2, typename RT>

  • RT max(T1 a, T2 b);

RT是不能根據(jù)函數(shù)的參數(shù)列表推導(dǎo)出來(lái)的,所以我們需要顯式的指定:

  • max<int, double, double>(4, 7.2);

或者我們改變模板參數(shù)列表順序,這種情況只需顯式的指定一個(gè)參數(shù)類型即可:

  • template<typename RT typename T1, typename T2> ? ? ?//RT變?yōu)榈谝粋€(gè)模板參數(shù)

  • RT max(T1 a, T2 b);

  • ...

  • max<double>(4, 7.2);

1.4.2 讓編譯器自己找出返回值類型

在C++11中,我們可以利用auto和trailing return type來(lái)讓編譯器找出返回值類型:

  • template <typename T1, typename T2>

  • auto max(T1 a, T2 b) -> decltype(b < a ? a : b) {

  • return b < a ? a : b;

  • }

decltype后面的文章會(huì)講到,這里只需知道它可以獲取到表達(dá)式的類型。

我們可以寫的更簡(jiǎn)單點(diǎn):

  • template <typename T1, typename T2>

  • auto max(T1 a, T2 b) -> decltype(true ? a : b) { ? ? ?// true ? a : b

  • return b < a ? a : b;

  • }

關(guān)于?:返回值規(guī)則可以參考這個(gè):Conditional Operator: ? :

看到true ? a : b不要奇怪為什么是true,這里的重點(diǎn)不是計(jì)算返回值,而是得到返回值類型。

在C++14中,我們可以省略trailing return type:

  • template<typename T1, typename T2>

  • auto max (T1 a, T2 b) {

  • return b < a ? a : b;

  • }

1.4.3 將返回值聲明為兩個(gè)模板參數(shù)的公共類型

c++11新特性std::common_type可以產(chǎn)生幾個(gè)不同類型的共同類型,其實(shí)核心意思跟上面說(shuō)的差不多:

  • template <typename T1, typename T2>

  • typename std::common_type<T1, T2>::type max(T1 a, T2 b) {

  • return b < a ? a : b;

  • }

在c++14中,可以更簡(jiǎn)單的寫:

  • template <typename T1, typename T2>

  • std::common_type_t<T1, T2> max(T1 a, T2 b) {

  • return b < a ? a : b;

  • }

這里使用_t后綴讓我們不用寫typename::type。類似的還有_v,這個(gè)在c++14的type traits里很常見(jiàn)。

1.5 默認(rèn)模板參數(shù)

這個(gè)很像函數(shù)的默認(rèn)參數(shù),直接看例子:

  • template <typename T1, typename T2, typename RT = std::common_type_t<T1, T2>>

  • RT max(T1 a, T2 b) {

  • return b < a ? a : b;

  • }


  • auto a = max(4, 7.2);

  • auto b = max<double,int,long double>(7.2, 4);

正如第二個(gè)用法,如果我們想顯示的指明RT的類型,必須顯示的指出全部三個(gè)參數(shù)類型。但是與函數(shù)默認(rèn)參數(shù)不同的是,我們可以將默認(rèn)參數(shù)放到第一個(gè)位置:

  • template <typename RT = long, typename T1, typename T2>

  • RT max(T1 a, T2 b) {

  • return b < a ? a : b;

  • }


  • int i;

  • long l;

  • max(i, l); ? ? ? ? ? ? ? ? ? ? // 返回值類型是long (RT 的默認(rèn)值)

  • max<int>(4, 42); ? ? ?//返回int,因?yàn)槠浔伙@式指定

1.6 重載函數(shù)模板

這個(gè)跟普通函數(shù)重載也類似:

  • // maximum of two int values:

  • int max(int a, int b) {

  • return b < a ? a : b;

  • }


  • // maximum of two values of any type:

  • template <typename T>

  • T max(T a, T b) {

  • return b < a ? a : b;

  • }


  • int main() {

  • max(7, 42); ? ? ? ? // calls the nontemplate for two ints

  • max(7.0, 42.0); ? ? // calls max<double> (by argument deduction)

  • max('a', 'b'); ? ? ?// calls max<char> (by argument deduction)

  • max<>(7, 42); ? ? ? // calls max<int> (by argument deduction)

  • max<double>(7, 42); // calls max<double> (no argument deduction)

  • max('a', 42.7); ? ? // calls the nontemplate for two ints

  • }

這里需要解釋下最后一個(gè)max('a', 42.7)因?yàn)樵谀0鍏?shù)類型推導(dǎo)過(guò)程中不允許類型自動(dòng)轉(zhuǎn)換,但是調(diào)用普通函數(shù)是允許的,所以這個(gè)會(huì)調(diào)用非模板函數(shù)。

ps. 由于函數(shù)模板重載,所以函數(shù)模板并不像類模板一樣可以進(jìn)行偏特化。

還有兩點(diǎn)關(guān)于重載的基本原則需要了解一下:

1.6.1 重載時(shí)最好不要隨便改變模板參數(shù)個(gè)數(shù),最好可以顯示的指定模板參數(shù)類型

下面是段有問(wèn)題的代碼:

  • // maximum of two values of any type (call-by-reference)

  • template <typename T> T const &max(T const &a, T const &b) {

  • return b < a ? a : b;

  • }


  • // maximum of two C-strings (call-by-value)

  • char const *max(char const *a, char const *b) {

  • return std::strcmp(b, a) < 0 ? a : b;

  • }


  • // maximum of three values of any type (call-by-reference)

  • template <typename T> T const &max(T const &a, T const &b, T const &c) {

  • return max(max(a, b), c); ? ? ? ? ? // error if max(a,b) uses call-by-value

  • }


  • int main() {

  • auto m1 = max(7, 42, 68); ? ? ? ? // OK


  • char const *s1 = "frederic";

  • char const *s2 = "anica";

  • char const *s3 = "lucas";

  • auto m2 = max(s1, s2, s3); ? ? ? ? // run-time ERROR

  • }

問(wèn)題出現(xiàn)在return max (max(a,b), c);,因?yàn)?code>char const *max(char const *a, char const *b)的參數(shù)是按值傳遞,max(a,b)會(huì)產(chǎn)生一個(gè)指向已經(jīng)銷毀的棧幀地址,這會(huì)導(dǎo)致未定義行為。

1.6.2 確保所有被重載的函數(shù)模板在使用時(shí)已經(jīng)被聲明定義

  • // maximum of two values of any type:

  • template <typename T>

  • T max(T a, T b) {

  • std::cout << "max<T>()\n";

  • return b < a ? a : b;

  • }


  • // maximum of three values of any type:

  • template <typename T>

  • T max(T a, T b, T c) {

  • return max(max(a, b), c);

  • }


  • // maximum of two int values:

  • int max(int a, int b) {

  • std::cout << "max(int,int) \n";

  • return b < a ? a : b;

  • }


  • int main() {

  • max(47, 11, 33); ? ?// max<T>()

  • }

這點(diǎn)很好理解。

鏈接:https://www.dianjilingqu.com/612129.html

C++模板——函數(shù)模板的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
九龙坡区| 宁国市| 汉阴县| 苏尼特左旗| 墨江| 英德市| 黄浦区| 武定县| 固始县| 武威市| 哈巴河县| 华安县| 汶川县| 佛学| 民勤县| 织金县| 阿图什市| 巩义市| 平阴县| 祥云县| 洪雅县| 慈利县| 莱州市| 灵寿县| 沛县| 萝北县| 张家界市| 金湖县| 崇礼县| 云梦县| 黄梅县| 福鼎市| 安宁市| 克拉玛依市| 桦川县| 阿坝| 潮安县| 黄石市| 祁阳县| 噶尔县| 扎兰屯市|