2013-05-29 48 views
7

我不明白應該如何使用以下功能。當我打電話給A::f時,我可以省略模板參數,但我不明白爲什麼。將參數包解壓到另一個模板聲明中意味着什麼?

template <typename... Args> 
struct A 
{ 
    template <Args...> 
    void f() {} 
}; 

int main() 
{ 
    A<int, bool> a; 
    a.f(); 
} 

具體來說,什麼是template <Args...>意思?我爲什麼可以離開模板參數進行函數調用來f

+1

這意味着它擴展到'template '因爲這是您在實例化類時做出的Args。但我不完全確定它是如何編譯的,因爲實際上將它改爲'template '並不是。 – chris

+1

我認爲這是一個編譯器錯誤 –

+1

...它應該像這樣使用,但它不能:http://ideone.com/gAQEox(注意:使用'template '擴展爲'template ' ,這很好:http://ideone.com/Q70BzL) – leemes

回答

5

template<typename ...Args>是一個可變模板。這意味着,您可以指定任意數量的模板類型參數,但我認爲您已經知道這一點。

每當Args...出現在模板代碼,這將是解壓(「擴展」)的類型實例化的。在你的例子中,這是int, bool。所以,你的類成爲,當完全展開,這樣的定義:

struct A<int, bool> 
{ 
    template <int, bool> 
    void f() {} 
}; 

這意味着,A<int,bool>::f()再次模板(參數拆包到另一個模板聲明,你叫吧),但這次非型同類型intbool模板參數(他們是匿名的),所以你可以例如像這樣的實例f()

a.f<1, true>(); 

不幸的是,g++似乎有一個錯誤,並且won't accept這段代碼,而它accepts你的代碼。

clang接受這兩個代碼。我希望在你的代碼中,clang不在乎intbool模板參數是否被忽略,但是它們在指定時不會抱怨(與g++相反)。

用例:

如果你要使用指定的值,就不能匿名(顯然)。你可以,例如,在f()這是用來「printf的」模板值提供格式字符串,像這樣:

template <Args ...values> 
void f(const char *fmt) { 
    std::printf(fmt, values...); 
} 

接着,下面的代碼

A<int> a; 
a.f<42>("The answer is %d!\n"); 

會打印:

The answer is 42! 

但是,使用上述語法(Args...擴展爲匿名非類型模板參數),模板參數本質上是無用

沒有指定值,它仍然編譯(這讓我感到驚訝!)並打印未初始化的值int值。

+0

是的,我想知道爲什麼'a.f <1, true>()'沒有編譯:) – 0x499602D2

+0

這是叮噹中的一個已知錯誤,它可以讓你忽略它。 –

+0

@ JohannesSchaub-litb是的,我猜對了。允許忽略非默認參數是沒有意義的。 – leemes

0

你可以保留模板參數的原因是因爲C++ 11有模板參數推理template<args ...>是一個可變參數模板,它基本上是一組可能不同的類型名稱。這個website解釋了模板參數的省略。從進一步閱讀編譯器可以推斷出的非類型模板參數的推論,我相信編譯器意識到它們從來沒有被使用(至少與clang一起使用)並根據它進行演繹,請閱讀演繹非類型模板參數部分website

+0

但是沒有什麼值得推導的參數,因爲它們是非類型參數'template ' – leemes

+0

在他的例子中,沒有類型,bool和int是類模板的一部分,而不是函數模板 – aaronman

+0

'f'是一個模板函數。它的模板有兩個int *和* bool *值,因爲'template '擴展爲'template '。 – leemes

相關問題