2013-02-26 44 views
0

我有一個關於在C++元編程中扣除類型的小問題。 有一定的功能做一些動作。爲什麼類型扣除不能按預期工作?

的main.cpp

template<typename T> void foo(T arg) { 
    // do some action on argument 
    std::cout << typeid(arg).name() << std::endl; 
} 


int main(int argc, char** argv) { 
    int array[100] = {0}; 
    std::cout << typeid(array).name() << std::endl; 
    foo(array); 

    return 0; 
} 

輸出:

A100_i 
Pi  

爲什麼ARG在功能FOO()具有在功能主(大於陣列一個另一種數據類型)

+0

我會說:錯誤的期望。可能很好的谷歌關鍵字:數組指針衰減。 – PlasmaHH 2013-02-26 09:45:01

+0

數以百計的問題已經發布到SO基礎上,由於數組衰減指針,通常涉及'sizeof'的誤解,但這是一種新穎的方法。 :-) – 2013-02-26 09:48:53

+0

您對標題添加CLOSED意味着什麼? – 2013-02-27 14:28:01

回答

3

因爲C風格數組被破壞。特別是,你不能 有一個C風格數組類型的函數參數;如果你寫 函數(忘記了暫時模板):

void foo(int arg[100]); 

語言需要編譯器來處理這個:

void foo(int* arg); 

(和100只是一個評論—這是由編譯器 忽略)。

爲了支持這在模板的情況下,如果 編譯器試圖匹配一個非參考模板參數, 它將數組參數轉換爲指針,並鍵入 扣將導致指針類型,而不是數組類型。

的結果是,你不應該寫期待一個C風格的數組(除爲main,在那裏你沒有選擇第二 參數)的函數(模板 或其他)。

由於此斷裂僅出於 C兼容性的原因,因此在涉及 引用時,C++不會遵循它。所以:

template < typename T, size_t N > 
void foo(T (&arg)[ N ]); 

將工作,並應在兩種情況下給你相同的結果。 如果你認爲你的函數可能被 C風格的數組和其他東西(例如std :: vector)調用,你可以使用 爲它們重載。上面的版本更專業, ,如果可能的話,將更喜歡更通用的版本。

更好的解決方案是完全避免C風格的數組,但是它們對初始化的靜態變量很有用;它只有 只有C風格的數組,你可以讓編譯器計數 的元素數量,並根據初始化列表定義數組 的大小。並有初始化靜態 ; std::vector將在 運行時計數初始值設定項,但用作靜態變量,可能會導致 命令的初始化問題。 C風格的陣列和

+1

+1瞭解詳細的答案。 – Nawaz 2013-02-26 10:07:25

6

實際上,當你將一個數組傳遞給一個函數時,它會衰減爲一個指針類型。因此推導出Tint*,而不是int[100]

如果你想防止腐爛,通過參考接受參數

template<typename T> void foo(T & arg) //Note `&` here! 
{ 
    // do some action on argument 
    std::cout << (typeid(arg).name() << std::endl; 
} 

現在它將打印你所期望的,即A100_i。見this online demo


問:爲什麼陣列衰減到指針類型當我們通過通過值

答案:因爲在C++陣列(和函數)不能由值傳遞。該語言不允許。相反,語言要求它們在作爲函數參數傳遞時衰減爲指針類型。爲了防止衰減,我們需要將它們作爲參考

+0

更重要的一點,也許是:當你定義一個具有數組類型的參數時,它會自動轉換爲指針的定義。 – 2013-02-26 10:05:44

+0

@JamesKanze:哦這絕對是更好,更準確。我希望OP閱讀這個評論以及你的答案。 :-) – Nawaz 2013-02-26 10:06:30

相關問題