日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

binarytreenode”使用 类 模板 需要 模板 参数列表_c++1117 模板核心知识(一)—— 函数模板...

發(fā)布時間:2025/3/21 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 binarytreenode”使用 类 模板 需要 模板 参数列表_c++1117 模板核心知识(一)—— 函数模板... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

  • 定義函數(shù)模板
  • 使用函數(shù)模板
  • 兩階段翻譯 Two-Phase Translation
    • 模板的編譯和鏈接問題
  • 多模板參數(shù)
    • 引入額外模板參數(shù)作為返回值類型
    • 讓編譯器自己找出返回值類型
    • 將返回值聲明為兩個模板參數(shù)的公共類型
  • 默認模板參數(shù)
  • 重載函數(shù)模板
    • 重載時最好不要隨便改變模板參數(shù)個數(shù),最好可以顯示的指定模板參數(shù)類型
    • 確保所有被重載的函數(shù)模板在使用時已經(jīng)被聲明定義

定義函數(shù)模板

template<typename?T>
T?max(T?a,T?b)?{
??return?b?}

使用函數(shù)模板

??std::cout?<7,42)?<std::endl;

??std::cout?<1.1,2.2)?<std::endl;

??std::cout?<"math","mathematics")?<std::endl;

模板不是被編譯成可以處理任何類型的單個函數(shù)。相反,編譯器會針對每一個使用該模板的類型生成對應的函數(shù)。例如,max(7,42)的調用在語義上相當于調用了:

int?max(int?a,int?b)?{
??return?b?}

double、string 同理。

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

兩階段翻譯 Two-Phase Translation

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

std::complex<float>?c1,c2;????????//不支持?max中的?
...
max(c1,c2);

模板會分成兩個階段進行”編譯“:

  • 在不進行模板instantiation的definition time階段,此時會忽略模板參數(shù),檢查如下方面:
    • 語法錯誤,包括缺失分號。
    • 使用未定義參數(shù)。
    • 如果 static assertion 不依賴模板參數(shù),會檢查是否通過 static assertion.
    在instantiation階段,會再次檢查模板里所有代碼的正確性,尤其是那些依賴模板參數(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

    }

    模板的編譯和鏈接問題

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

    • 將類或者其他類型聲明放在頭文件(.hpp、.H、.h、.hh、.hxx)中。
    • 將函數(shù)定義等放到一個單獨的編譯單元文件中(.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?
    #include?
    #include?"myfirst.hpp"
    //?implementation/definition?of?template
    template<typename?T>void?printTypeof?(T?const&?x)?{
    ??std::cout?<typeid(x).name()?<'\n';
    }

    在另一個文件中使用該模板:

    //?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++中,當編譯階段發(fā)現(xiàn)一個符號(printTypeof)沒有定義只有聲明時,編譯器會假設它的定義在其他文件中,所以編譯器會留一個”坑“給鏈接器 linker,讓它去填充真正的符號地址。

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

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

    多模板參數(shù)

    template<typename?T1,?typename?T2>
    T1?max?(T1?a,?T2?b)?{
    ????return?b?}
    ...
    auto?m?=?max(4,?7.2);???????//?注意:返回類型是第一個模板參數(shù)T1 的類型

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

    一般有三個方法解決這個問題:

    • 引入額外模板參數(shù)作為返回值類型
    • 讓編譯器自己找出返回值類型
    • 將返回值聲明為兩個模板參數(shù)的公共類型,比如 int 和 float,公共類型就是 float

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

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

    template<typename?T1,?typename?T2,?typename?RT>
    RT?max(T1?a,?T2?b);

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

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

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

    template<typename?RT?typename?T1,?typename?T2>??????//RT變?yōu)榈谝粋€模板參數(shù)
    RT?max(T1?a,?T2?b);
    ...
    max<double>(4,?7.2);

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

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

    template?<typename?T1,?typename?T2>
    auto?max(T1?a,?T2?b)?->?decltype(b??{return?b?}

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

    我們可以寫的更簡單點:

    template?<typename?T1,?typename?T2>
    auto?max(T1?a,?T2?b)?->?decltype(true???a?:?b)?{??????//?true???a?:?b
    ??return?b?}

    關于?:返回值規(guī)則可以參考這個:[Conditional Operator: ? :]()

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

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

    template<typename?T1,?typename?T2>auto?max?(T1?a,?T2?b)?{
    ????return?b?}

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

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

    template?<typename?T1,?typename?T2>
    typename?std::common_type::type?max(T1?a,?T2?b)?{return?b?}

    在 c++14 中,可以更簡單的寫:

    template?<typename?T1,?typename?T2>
    std::common_type_t?max(T1?a,?T2?b)?{
    ??return?b?}

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

    默認模板參數(shù)

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

    template?<typename?T1,?typename?T2,?typename?RT?=?std::common_type_t>
    RT?max(T1?a,?T2?b)?{return?b?}auto?a?=?max(4,?7.2);auto?b?=?max<double,int,long?double>(7.2,?4);

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

    template?<typename?RT?=?long,?typename?T1,?typename?T2>
    RT?max(T1?a,?T2?b)?{
    ??return?b?}

    int?i;
    long?l;

    max(i,?l);?????????????????????//?返回值類型是long?(RT?的默認值)
    max<int>(4,?42);??????//返回int,因為其被顯式指定

    重載函數(shù)模板

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

    //?maximum?of?two?int?values:
    int?max(int?a,?int?b)?{
    ??return?b?}

    //?maximum?of?two?values?of?any?type:
    template?<typename?T>
    T?max(T?a,?T?b)?{
    ??return?b?}

    int?main()?{
    ??max(7,?42);?????????//?calls?the?nontemplate?for?two?ints
    ??max(7.0,?42.0);?????//?calls?max?(by?argument?deduction)
    ??max('a',?'b');??????//?calls?max?(by?argument?deduction)
    ??max<>(7,?42);???????//?calls?max?(by?argument?deduction)
    ??max<double>(7,?42);?//?calls?max?(no?argument?deduction)
    ??max('a',?42.7);?????//?calls?the?nontemplate?for?two?ints
    }

    這里需要解釋下最后一個max('a', 42.7)。因為在模板參數(shù)類型推導過程中不允許類型自動轉換,但是調用普通函數(shù)是允許的,所以這個會調用非模板函數(shù)。

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

    還有兩點關于重載的基本原則需要了解一下:

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

    下面是段有問題的代碼:

    //?maximum?of?two?values?of?any?type?(call-by-reference)
    template?<typename?T>?T?const?&max(T?const?&a,?T?const?&b)?{
    ??return?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
    }

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

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

    //?maximum?of?two?values?of?any?type:
    template?<typename?T>
    T?max(T?a,?T?b)?{
    ??std::cout?<"max()\n";return?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?}int?main()?{
    ??max(47,?11,?33);????//?max()
    }

    這點很好理解。

    (完)

    《新程序員》:云原生和全面數(shù)字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的binarytreenode”使用 类 模板 需要 模板 参数列表_c++1117 模板核心知识(一)—— 函数模板...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。