簡體   English   中英

重載模板函數時顯式特化和常規函數之間的區別

[英]Difference between explicit specialization and regular functions when overloading a template function

我今天開始了。 這里是n00b問題7:

當您嘗試重載模板函數時,顯式特化和常規函數之間的區別是什么?

使用顯式專業化的適當情況是什么? 我不太明白:

#include <iostream>

template <typename s> void test(s var1);
template <> void test<int>(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

template <> void test<int>(int var1){
    std::cout << "int " << var1 << std::endl;
}

反對:

#include <iostream>

template <typename s> void test(s var1);
void test(int var1);

int main(){
    test(1);
    test(1.1);
    test("hello!!");
    return 0;
}

template <typename s> void test(s var1){
    std::cout << var1 << std::endl;
}

void test(int var1){
    std::cout << "int " << var1 << std::endl;
}

顯式專用模板函數和非模板常規函數之間沒有區別,除了當編譯器為函數調用尋找匹配的簽名類型時,它將首先選擇匹配的非模板函數在嘗試實例化可能滿足所需簽名匹配的任何可用模板函數之前所需的簽名。

如果您要在不是模板函數的頭文件中聲明和定義函數,則必須將該函數聲明為inline函數。 這是因為模板函數不是與代碼模塊鏈接的實際函數,直到它實際被實例化為止。 然后鏈接器在編譯代碼模塊后拋棄該實例化。 如果鏈接器沒有這樣做,那么每當.cpp文件包含頭文件時,鏈接器就會抱怨函數的重復定義。 在非模板函數上使用inline關鍵字在編譯器級別具有類似的效果,因為無論何時在.cpp文件中使用該函數,編譯器都會使用inline函數中的函數代碼的主體替換該函數調用。在頭文件中,並避免使用相關堆棧活動記錄設置和清理的函數調用的開銷。 因此,鏈接器不會抱怨函數的重復定義。

我不是專家,但是當我想定義不同的返回類型時,我的經驗是使用模板(和專業化)。 您不能重載函數的返回類型。

一個主要的區別是:顯式專業化根本不參與重載。

template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);

f("hello")調用不會考慮任何明確的特化。 它只會獲取所有模板,並推斷出它們的模板參數。 上面的T將推導為char[6] ,因此不會選擇專業化。

如果改為重載函數模板,則具有完全不同的特征。

template<typename T> void f(T const&);
void f(char const * const&);

調用它,它將選擇第二個函數,因為生成的特化的(char const(&)[6])參數和(char const * const&)參數同樣匹配參數,但第二個函數是非-template函數,因此最終是優選的。

當編譯器遇到函數調用時,它首先查找非模板函數definiton,然后查找顯式專用模板,最后查找其簽名與函數調用匹配的模板定義。 因此,例如,如果您有明確定義的模板和模板,那么編譯器將用於明確定義的模板。 因此,當您希望以與模板處理它的方式不同的方式處理特定數據類型時,應使用明確的特殊模板。

顯式特化的另一個用途是當你想要“重載”一個不帶任何參數的函數時。 您可以使用顯式特化來為函數提供不同的定義以處理不同的數據類型。

恕我直言,當你要使用顯式模板參數調用該函數時,應該使用function template顯式特化。 例如

test<int>(myClass); // no argument for 'int' -> declare test() as template specialization

在其他情況下,您應始終使用常規專業化。 例如

test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized

從技術上講,函數的正常和顯式模板特化之間沒有區別。 普通的專用版本完全獨立於template功能。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM