[英]Why I can't pass string literals to const char* const& in this specialized function template
為什么在專門的 function 模板中將字符串文字傳遞給const char* const&是非法的,而傳遞給const char*是合法的?
事情是這樣的。 C++ Primer中有兩個關於模板特化的練習:
練習 16.63:定義一個 function 模板來計算給定值在向量中出現的次數。 通過向程序傳遞一個雙精度向量、一個整數向量和一個字符串向量來測試您的程序。
練習 16.64:編寫上一個練習中模板的專用版本來處理 vector<const char*> 和一個使用該專用化的程序。
下面的代碼是我的答案,當我將字符串文字傳遞給這個專門的計數function 時出現編譯錯誤。
// Count the number of occurrences of a given value in a vector
template <typename T>
std::size_t count(const std::vector<T>& vec, const T& value)
{
std::size_t i = 0;
for (const auto& v : vec) {
if (v == value)
++i;
}
return i;
}
// A specialized version where T = const char*
template <>
std::size_t count(const std::vector<const char*>& vec, const char* const& value)
{
std::size_t i = 0;
for (const auto& v : vec) {
if (!strcmp(v, value))
++i;
}
return i;
}
int main()
{
std::vector<const char*> sVec{ "cpp", "primer", "cpp", "fifth", "edition", "Cpp", "cpp" };
// Error message: no instance of function template "count" matches the argument list,
// argument types are: (std::vector<const char *, std::allocator<const char *>>, const char [4])
std::cout << count(sVec, "cpp") << std::endl;
return 0;
}
此外,在非模板 function 中將字符串文字傳遞給const char* const&是完全可以的,這讓我感到困惑。
void test(const char* const& str)
{
std::cout << str << std::endl;
}
int main()
{
test("cpp"); // Prints "cpp" as expected
return 0;
}
數組和指針是不同的類型。
由於默認轉換,您可以將數組作為指針參數傳遞。
模板就是 function 的“模板”。
沒有具體的function來匹配已經指定的參數。 所以編譯器試圖從參數中生成一個 function 並且無法匹配,所以它失敗了。
但是當你指定模板參數時,編譯器確切地知道你想要哪個 function,生成它,然后嘗試使用調用函數的標准規則調用 function,這允許它進行轉換。
當你有模板 function 定義時,對 function arguments 的要求更嚴格。
在這種情況下,它將嘗試匹配數組並從模板生成 function 並失敗。 因此無法撥打 function。
你可以專攻:
// A specialized version where T = const char[ArraySize]
template<std::size_t ArraySize>
std::size_t count(const std::vector<const char*>& vec, const char (&value)[ArraySize])
{
return count<const char*>(vec, value);
}
- 編輯
或者專門定義一個模板參數function,里面定義了一個具體的function來調用。
您不會“傳遞給 function 模板專業化”。 該調用是根據原始模板定義推導出來的(不管任何專業化),如果成功則推導出一個類型。 然后,如果推導類型存在專門化,則將調用該專門化。
錯誤消息是關於類型推導失敗的。 即使刪除專業化,您也應該看到完全相同的錯誤。
類型推導失敗,因為T
出現在兩個不同的參數中,但推導結果因每個參數而異:
vector<const char *>
推導vector<T>& vec
產生T=const char *
"cpp"
推導const T& value
產生T=const char[4]
。 僅當推導的T
的所有實例都產生相同類型時,推導才會成功。 沒有通過考慮可用轉換來協調不同類型的額外步驟。
解決該問題的一種方法是使用重載而不是特化(即刪除文本template <>
)。 然后是一個由非模板 function 和推導結果(如果有)組成的重載集。 如果演繹失敗,正如它所做的那樣,這不是錯誤,因為重載集仍然包含一些東西。
哦,我將代碼更改為std::cout << count<const char*>(sVec, "cpp") << std::endl;
然后一切都很好。 編譯器似乎將字符串文字 "cpp" 視為const char [4]而不是const char* const& ,因此我必須明確指定模板參數。 想知道為什么會這樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.