簡體   English   中英

在模板參數中,哪些規則允許編譯器推斷數組的項數?

[英]In a template argument, what rules allow the compiler to infer the number of items of an array?

鑒於下面的兩個程序 - 除了模板 function len()的定義之外,其他程序相同:

// ================================
//  a.cc
// ================================
#include <iostream>

template<class T, std::size_t n>
std::size_t len(T (&v)[n]) { return n; }

int main()
{
    int arr[] = { 1,2,3 };

    std::cout << len(arr) << std::endl;
}
// ================================
//  b.cc
// ================================
#include <iostream>

template<class T, std::size_t n>
std::size_t len(T v[n]) { return n; }

int main()
{
    int arr[] = { 1,2,3 };

    std::cout << len(arr) << std::endl;
}

使用 g++ 時,第一個程序按預期編譯並運行。 但第二個不編譯。 這是診斷:

 b.cc: In function 'int main()': b.cc:13:25: error: no matching function for call to 'len(int [3])' std::cout << len(arr) << std::endl; ^ b.cc:7:13: note: candidate: template<class T, long unsigned int n> std::size_t len(T*) std::size_t len(T v[n]) { return n; } ^ b.cc:7:13: note: template argument deduction/substitution failed: b.cc:13:25: note: couldn't deduce template parameter 'n' std::cout << len(arr) << std::endl;

為什么編譯器能夠在第一種情況下推斷出數組中的項目數,而在第二種情況下卻不能? 是什么使得在 C++11 或 C++17 標准中,必須寫T (&v)[n]而不是T v[n]

在這:

template<class T, std::size_t n>
std::size_t len(T (&v)[n]) { return n; }

v是對T[n]數組的引用 數組 ( n ) 的大小是數組類型的一部分。 所以n可以從傳入的任何固定大小的數組中推導出來。

在這:

template<class T, std::size_t n>
std::size_t len(T v[n]) { return n; }

在 function 參數T v[n]中, n被忽略,並且T v[]只是T *v的語法糖(您可以在錯誤消息中看到 - std::size_t len(T*) )。 因此,即使傳入了一個固定長度的數組,實際上也沒有什么可以推導出n的。

[temp.deduct] [強調我的]涵蓋了模板參數推導:

/1 當引用 function 模板特化時,所有模板 arguments 都應具有值。 這些值可以明確指定,或者在某些情況下,可以從使用中推導出來或從默認模板參數中獲取。

/2(...關於顯式模板參數列表:此處不相關)

/3 執行此替換后,執行 [dcl.fct] 中描述的 function 參數類型調整。 [ 示例:“void (const int, int[5])”的參數類型變為“void( )(int,int )”。 —結束示例] [...]

注意對 [dcl.fct] 和 /3 中的相關(非規范)示例的引用,顯示了將值類型數組 function 參數int[N]調整為int* ,這意味着非類型模板參數N不是從傳遞給值類型數組參數的 arguments 推導出來(在此上下文中N無用/忽略)。

從 function 調用中推導模板參數,特別是包含在[temp.deduct.call] 中 並且區分您的兩個示例的相關部分是[temp.deduct.call]/2.1 ,它表示如果調用的參數(表示為A )是數組類型,並且參數類型(表示為P不是參考類型,指針類型用於類型推導:

/2 如果P不是引用類型:

  • (2.1)如果A是數組類型,則使用數組到指針標准轉換產生的指針類型代替A進行類型推導; 否則, [...]

而當P引用類型時,如下例所示:

 template<class T, std::size_t n> std::size_t len(T (&v)[n]) { return n; }

[temp.deduct.call]/2.1 不適用,並且對於以下以數組為參數對名為len的 function 的調用

int arr[] = { 1,2,3 };
(void)len(arr);

名稱查找將找到 function 模板len ,隨后將使用P as T[N] (根據[temp.deduct.call]/3 )和A as int[3]應用模板參數推導,用於單個 function 參數len ,將T推導為int ,將N推導為3 ,用於參數類型P的完整類型推導; 根據[temp.deduct.type]/1

模板 arguments 可以在幾種不同的上下文中推導出來,但在每種情況下,都會將根據模板參數指定的類型(稱為P )與實際類型(稱為A )進行比較,並嘗試查找模板參數值(類型參數的類型、非類型參數的值或模板參數的模板),這將使P在替換推導值(稱為推導A )后與A兼容。

即,非類型模板參數N是單個 function 參數類型的一部分(類型模板參數T也是如此)。

第一個相當於一個指針。 請參閱dcl.fct (由temp.deduct調用,正如@dfrib 的回答所解釋的那樣):

使用以下規則確定 function 的類型。 ...確定每個參數的類型后,將任何類型為“ T的數組”的參數調整為“指向T的指針”。 ...

這不適用於第二個,因為它是對數組的引用(沒有 arrays 引用,但對 arrays 的引用很好)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM