1、報錯現象:
1.1、執行的代碼:
string s = "Abcd. ,,cD";
transform(s.begin(), s.end(), s.begin(), tolower);
tolower作用:是大寫字母則轉換爲小寫,不是字母則保持不動。
1.2、提示的錯誤:
Line 5: Char 9: fatal error: no matching function for call to 'transform'
transform(s.begin(), s.end(), s.begin(), tolower);
^~~~~~~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/stl_algo.h:4293:5:
note: candidate template ignored: couldn't infer template argument '_UnaryOperation'
1 error generated.
顯示無法推斷模板參數。
2、報錯原因:
在<cctype>
裏面聲明瞭一個C版本的函數tolower
:
int tolower(int);
而在<local>
中間也聲明瞭一個函數模板tolower
:
template <class charT>
charT tolower( charT c , const locale& loc );
如果這兩個頭文件都同時包含到程序中來的話(C++標準頭文件可能會包含另外的標準頭文件。例如<iostream>
,會包含<locale>
或<cctype>
頭文件。這樣,包含<iostream>
可能會引入<locale>
或<cctype>
),由於這些 tolower
函數都位於同一 std
名字空間,於是形成了函數重載。這樣的話,==transform
函數(也是一個模板函數)的第四個參數是tolower 的時候,此時給定的 tolower
只是作爲一個函數指針使用,缺乏類型推導所需要的函數參數信息,所以無法推導出函數的類型,也就無法決定使用哪一個重載函數。
3、多種方法可以解決:
3.1、指明函數類型:
transform( s.begin(), s.end(), s.begin(), (int(*)(int))tolower);
或者
int (*pf)( int ) = tolower; // pf 是一個函數指針,其類型已經明確。
transform( s.begin(), s.end(), s.begin(), pf );
3.2、使用包裝函數:避免直接使用 tolower 函數由於重載帶來的問題
int my_tolower( int c )
{
return tolower( c ); // 根據 c 的類型可以確定使用 tolower 的哪個重載函數。
}
// my_tolower 是非模版非重載函數,避免了函數重載帶來的類型解析問題。
transform( s.begin(), s.end(), s.begin(), my_tolower );
3.3、調用全局下的tolower函數:
非模板函數的 tolower
其實是來自於標準 C 庫函數,因此在 C++ 標準庫中它同時位於全局和 std 名字空間。既然 std 名字空間內 tolower 函數有可能形成函數重載,但是在全局名字空間中的 tolower 函數卻只有一個,所以也可以直接使用全局名字空間中的 tolower:
transform( s.begin(), s.end(), s.begin(), ::tolower);
參考資料:no matching function for call to ‘transform
總結:
1、transform模板函數調用tolower函數報錯是因爲無法決定使用哪一個tolower的重載函數。
2、最簡單的調用全局下的::tolower
函數避免衝突。