2013-07-11 57 views
2

下面的代碼編譯:這個函數模板調用爲什麼起作用?

template<int...> 
struct Indices {}; 

template<int J, int ...I> 
void foo(Indices<I...>) {} 

int main(int argc, char **argv) 
{ 
    foo<2>(Indices<3,4,5>()); //why does this work? 
    return 0; 
} 

在函數調用,在我看來,該J參數成爲2...I參數變爲3,4,5

但是,它爲什麼這樣工作?我只指定2foo<2>這意味着我指定J2...I爲無。爲什麼我仍然可以通過Indices參數指定...I?這裏使用了什麼模板機制?

更新:目前的答案並不能解釋爲什麼我可以有一個參數沒有推導(明確指定),但推導出其他參數。這個工作到底是什麼時候?我希望我不依賴於未定義的行爲。標準允許我在上面做什麼?

+0

當你說'富<2>(指數<3,4,5>)',你輸入一個類型'指數<3,4,5>'入模板函數。由於輸入類型在編譯時已知,並且該類型對應於第二個模板參數,因此編譯器可以匹配'<3,4,5>'和''並生成正確的函數。 – Suedocode

回答

2

它允許指定的參數只有部分函數調用(第一批),如果有可能推斷在編譯時間等。例如:

template<typename Ret, typename Arg> 
Ret cast(Arg x){ 
    return x; 
} 

cast<double>(5); 

實際上可能甚至編譯此代碼:

template<int...> 
struct Indices {}; 

template<int J, int ...I> 
void foo(Indices<I...>) {} 

int main(int argc, char **argv) 
{ 
    foo<2,3>(Indices<3,4,5>()); //ok 2,3,4,5 starts with 2,3 
    return 0; 
} 

但不是這一個:

template<int...> 
struct Indices {}; 

template<int J, int ...I> 
void foo(Indices<I...>) {} 

int main(int argc, char **argv) 
{ 
    foo<2,1>(Indices<3,4,5>()); //no way to make x,3,4,5 start with 2,1 
    return 0; 
} 

參見§ 14.1.8部分3標準的C++ 11( N3242草案)。

可以推斷(14.8.2)或者從默認模板參數獲得 尾隨模板參數可以從 明確的模板參數列表被省略。未被推導出的尾隨模板參數包 (14.5.3)將被推斷爲模板參數的空序列 。如果可以推導出所有模板參數,則可以全部省略它們;在這種情況下,空模板參數<>本身也可以被省略。在扣除是 完成和失敗的情況下,或者在沒有完成扣除的上下文中,如果指定了 模板參數列表,並且它與任何默認的 模板參數一起標識單個功能模板 專業化,則模板 - id是功能 模板專用化的左值。

6

參數解包...I由編譯器從函數參數中推導出。它被稱爲template argument deduction

這裏有一些簡單,但有用的例子:

template<typename T> 
void f(T const&) {} 

f(10); //T is deduced as int 
f(10.0); //T is deduced as double 
f("10"); //T is deduced as char[3] 

標準庫中的許多功能函數模板,並經常模板參數推導。這裏有一個例子:

std::vector<int> vi; 
std::vector<std::string> vs; 
//... 
std::sort(vi.begin(), vi.end()); //template argument deduction 
std::sort(vs.begin(), vs.end()); //template argument deduction 

這裏std::sort是一個函數模板,但你可以看到,我們沒有明確地傳遞模板參數。這是因爲模板參數是由編譯器本身從函數參數中推導出來的。

希望有所幫助。

+0

我不知道我可以推導出一些參數,還有其他推理參數。你能否詳細說明一下? –

+2

@ roger.james:好吧,現在你做了。使用函數模板,您可以明確指定以第一個開始的參數並隨時停止。編譯器會嘗試推導出其餘部分。 – AnT

2

要添加到nawaz答案:必須提供無法推斷的模板參數,並且提供的模板參數必須按照定義的順序。這意味着如果模板參數可能需要提供,最好先將其放在模板參數列表中。例如

template<typename A, typename B> A foo(B); 
template<typename B, typename A> A bar(B); 

auto x = foo<int>(0.0);  // A=int, B=double; 
auto y = foo<int,double>(0); // A=int, B=double, argument implicitly cast to double 
auto z = bar<int>(0);   // error: cannot deduce A 
auto w = bar<int,double>(0); // A=double, B=int; 

在兩種情況下可以B(從該函數的參數類型)來推斷,但是A不能。因此foo更方便,因爲只有一個模板參數必須提供。使用bar,第一個模板參數是可以推出的,但不是第二個。因此,都必須提供。 (只是爲了澄清,長寧autodoubleint使得w.r.t.手頭上的問題沒有區別。)

相關問題