transform模板函數調用tolower函數報錯原因、解決辦法

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函數避免衝突。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章