2016-04-07 106 views
1

我想了解和了解可變參數模板的概念。 我碰到this例子就是Variadic模板示例不編譯

#include <iostream> 
using namespace std; 

//Output function to output any type without type specifiers like printf() family 
template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    cout << t << ' '; 
    if (sizeof...(p)) { output(p...); } 
    else { cout << '\n'; } 
} 

//Since variadic templates are recursive, must have a base case 
void output() { cout << "\n"; } 

//Test it 
int main() 
{ 
    //output(); 
    output('5', 2); 

    return(0); 
} 

然而,當我嘗試運行它,我得到的錯誤

main.cpp: In instantiation of 'void output(T, P ...) [with T = int; P = {}]': 
main.cpp:10:29: required from 'void output(T, P ...) [with T = char; P = {int}]' 
main.cpp:21:16: required from here 
main.cpp:10:29: error: no matching function for call to 'output()' 
    if (sizeof...(p)) { output(p...); } 
          ^
main.cpp:7:6: note: candidate: template<class T, class ... P> void output(T, P ...) 
void output(T t, P ...p) 
    ^
main.cpp:7:6: note: template argument deduction/substitution failed: 
main.cpp:10:29: note: candidate expects at least 1 argument, 0 provided 
    if (sizeof...(p)) { output(p...); } 
          ^

我如何能解決它的任何建議。由於

+3

交換兩個'output'重載。 –

+0

這不是_running_,那是_compiling_。我真的很想知道可變模板如何導致運行時錯誤。 – MSalters

回答

4

交換機的輸出函數聲明的順序:

//Since variadic templates are recursive, must have a base case 
void output() { cout << "\n"; } 

//Output function to output any type without type specifiers like printf() family 
template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    cout << t << ' '; 
    if (sizeof...(p)) { output(p...); } 
    else { cout << '\n'; } 
} 

中的重載決策規則得到質樸的模板函數,所以編譯器只是認爲,迄今已宣佈過載,並沒有考慮你的非模板。在編寫多個重載時,其中一個或多個是模板函數,聲明順序很重要。

+0

你能解釋一下發生了什麼嗎? – MistyD

+0

感謝您對清除 – MistyD

+2

聲明順序無關:http:// ideone。com/2GHhj0 –

1

T t其餘的將是第一個參數和P ...p

output('5', 2); 
//  ^

你把功能void output()下方,這不是可見

爲了解決這個問題,你可以聲明上面的函數,這樣可以看出:

void output(); 

或者與其他一個以上的無參數移動功能:

void output() { cout << "\n"; } 

template <typename T, typename ...P> 
void output(T t, P ...p) { // ... } 
2

它更復雜的不僅僅是聲明順序。看到這個答案:Switch passed type from template

template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    cout << t << ' '; 
    if (sizeof...(p)) { output(p...); } // HERE 
    else { cout << '\n'; } 
} 

無論功能是否實際上是調用它必須存在。你不能在一個函數中有一個分支,雖然從來沒有執行過,但會導致語法錯誤。因此您的支票sizeof...(p)是沒有意義的。

因此,爲了使你的代碼更清晰,因爲它完全表達自己,並沒有多餘的東西,改成這樣:

void output() { cout << "\n"; } 

//Output function to output any type without type specifiers like printf() family 
template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    cout << t << ' '; 
    output(p...); 
} 

您還沒有按照這個順序來定義它們,雖然這很容易。你可以這樣做:

void output(); 

//Output function to output any type without type specifiers like printf() family 
template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    cout << t << ' '; 
    output(p...); 
} 

void output() { cout << "\n"; } 

甚至這樣的:

template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    void output(); 
    cout << t << ' '; 
    output(p...); 
} 

void output() { cout << "\n"; } 

編輯:其實,可以避免爲0參數版本的需要:

template < typename T > 
void output(T t) { cout << t << "\n"; } 

//Output function to output any type without type specifiers like printf() family 
template <typename T, typename ...P> 
void output(T t, P ...p) 
{ 
    cout << t << ' '; 
    output(p...); 
} 
+2

最後一個不起作用。本地輸出聲明隱藏了模板。 –

+0

你說得對。我的錯。留下學習的目的。 –