![](/img/trans.png)
[英]Why compiler said “candidate template ignored: couldn't infer template argument 'InputIterator'”?
[英]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.