1. 程式人生 > 其它 >report service 報表 引數 預設值 int_C++11支援函式模板的預設模板引數

report service 報表 引數 預設值 int_C++11支援函式模板的預設模板引數

技術標籤:report service 報表 引數 預設值 int

在C++98/03 標準中,類模板可以有預設的模板引數,如下:

template <typename T, typename U = int, U N = 0>struct Foo{    // ...};

但是卻不支援函式的預設模板引數:

template <typename T = int>  // error in C++98/03: default template argumentsvoid func(){    // ...}

現在這一限制在 C++11 中被解除了。上面的 func 函式在 C++11 中可以直接使用,程式碼如下:

int main(void){    func();   //T = int    return 0;}

此時模板引數 T 的型別就為預設值 int。從上面的例子中可以看出,當所有模板引數都有預設引數時,函式模板的呼叫如同一個普通函式。但對於類模板而言,哪怕所有引數都有預設引數,在使用時也必須在模板名後跟隨<>來例項化。


除了上面提到的部分之外,函式模板的預設模板引數在使用規則上和其他的預設引數也有一些不同,它沒有必須寫在引數表最後的限制。甚至於,根據實際場景中函式模板被呼叫的情形,編譯器還可以自行推匯出部分模板引數的型別。
這意味著,當預設模板引數和編譯器自行推匯出模板引數型別的能力一起結合使用時,程式碼的書寫將變得異常靈活。我們可以指定函式中的一部分模板引數採用預設引數,而另一部分使用自動推導,比如下面的例子:

template R = int, typename R func(U val){    return val;}int main(){    func(97);               // R=int, U=int    func(97);         // R=char, U=int    func(97);  // R=double, U=int    return 0;}

C++11 標準中,我們可以像 func(97) 這樣呼叫模板函式,因為編譯器可以根據實參 97 自行推匯出模板引數 U 的型別為 int,並且根據返回值 val=97 推匯出 R 的型別也為 int;而 func(97) 手動指定了模板引數 R 的型別為 char(預設模板引數將無效),並通過實參 97 推匯出了 U = int;最後 func(97) 手動指定的 R 和 U 的型別值,因此無需編譯器自行推導。


再次強調,當預設模板引數和自行推導的模板引數同時使用時,若無法推匯出函式模板引數的型別,編譯器會選擇使用預設模板引數;如果模板引數即無法推匯出來,又未設定其預設值,則編譯器直接報錯。例如:

template <typename T, typename U = double>void func(T val1 = 0, U val2 = 0){    //...}int main(){    func('c'); //T=char, U=double    func();    //編譯報錯    return 0;}

其中,func('c') 的這種呼叫方式,編譯器通過實參 'c' 可以推匯出 T=char,但由於未傳遞第 2 個實參,因此模板引數 U 使用的是預設引數 double;但 func() 的呼叫方式是不行的,雖然 val1 設定有預設值,但編譯器無法通過該預設值推匯出模板引數 T 的型別。由此不難看出,編譯器的自動推導能力並沒有想象的那麼強大。


總的來說,C++11 支援為函式模板中的引數設定預設值,在實際使用過程中,我們可以選擇使用預設值,也可以嘗試由編譯器自行推導得到,還可以親自指定各個模板引數的型別。

c56f6e25b5b390f2019089e1a0e3843a.png