2010-09-09 43 views
2

重載函數我下面O'Reilly出版的書C++食譜和我嘗試的一個例子,這裏是代碼:沒有編制

#include <string> 
#include <iostream> 
#include <cctype> 
#include <cwctype> 

using namespace std; 

template<typename T, typename F> 
void rtrimws(basic_string<T>& s, F f){ 
    if(s.empty()) 
     return; 

    typename basic_string<T>::iterator p; 
    for(p = s.end(); p != s.begin() && f(*--p);); 

    if(!f(*p)) 
     p++; 

    s.erase(p, s.end()); 
} 

void rtrimws(string& ws){ 
    rtrimws(ws, isspace); 
} 

void rtrimws(wstring& ws){ 
    rtrimws(ws, iswspace); 
} 

int main(){ 
    string s = "zing   "; 
    wstring ws = L"zonh  "; 

    rtrimws(s); 
    rtrimws(ws); 

    cout << s << "|\n"; 
    wcout << ws << "|\n"; 
} 

當我嘗試編譯它,我得到以下錯誤

trim.cpp: In function ‘void rtrimws(std::string&)’: 
trim.cpp:22: error: too many arguments to function ‘void rtrimws(std::string&)’ 
trim.cpp:23: error: at this point in file 

我不明白什麼是錯的。如果我不使用字符版本(字符串),而只使用wchar_t版本,則一切運行平穩。

順便說,我使用的克++ 4.4.3在Ubuntu機64個比特

+1

順便說一下,它在VC++上編譯得很好 – 2010-09-09 19:20:44

+0

+1:好問題 – Chubsdad 2010-09-10 01:43:19

+0

在關閉此線程之前,爲了學習更多一點,我想討論一些事情。該代碼當然在VC++編譯,我沒有任何問題嘗試,但它不在GCC。函數isspace在cctypes.h中聲明爲__exctype(isspace);這是真正的extern int isspace(int)throw() – Sambatyon 2010-09-11 08:16:58

回答

1

isspace也是用C模板++,它接受一個模板字符,並與它使用的小std::ctype<T>給定的字符分類(語言環境,因此它不能下定決心採取什麼樣的版本,因此忽略模板)。

嘗試指定您的意思是C兼容版本:static_cast<int(*)(int)>(isspace)。編譯器之間的差異可能來自編譯器中重載函數名稱的扣除處理不一致 - 請參閱此clang PR。在費薩爾的第一套測試案例中查看類似案例的第二個案例。


有人指出,在IRC這個代碼將使用charisspace - 但isspace需要int,並要求給予在unsigned char值或EOF範圍內的值。現在,如果在您的PC上簽名了char並存儲了否定的非EOF值,則會導致未定義的行爲。

我建議像@Kirill在評論中說的那樣做,只是使用模板化的std::isspace - 那麼您也可以擺脫函數對象參數。

+0

我試圖尋找isspace的定義,它看起來不像模板。它實際上是用marco __exctype定義的,它擴展爲「extern int isspace(int)throw()」 – Sambatyon 2010-09-12 14:55:18

+0

@Sambatyon,然後你在錯誤的文件中查找。無論如何,你已經接受了一個嘗試/猜測答案:「試試xyz也許它有效,但不要爲什麼!!」。應該避免這些答案不合理。因爲下一次你遇到這個問題時,你會嘗試他的工作,也許它不會工作,然後你不能自己修復它,因爲你不知道*爲什麼*問題首先出現。 – 2010-09-12 19:56:00

0

這是因爲isspace位於c模板函數++。它不能推導出F。如果你想使用的isspaceÇ變種,你可以完全限定其名稱如下:

void rtrimws(string& ws){ 
    rtrimws(ws, ::isspace); // this will use isspace from global namespace 
          // C++ version belongs to the namespace `std` 
} 

這是一個多好的樣品,爲什麼你不應該使用using namespace std

+1

請注意,當你使用':: isspace'時,你需要包含'ctype.h'。在使用像Cctype這樣的C++頭文件時,是否聲明瞭全局名稱是未指定的。 – 2010-09-09 19:43:02

+0

同意。實際上不需要傳遞'isspace'作爲參數。 OP可以在'rtrimws'模板中使用'isspace'函數的模板化C++版本。 – 2010-09-09 19:49:23

+0

除了我會失去這個學習新東西的機會:( – Chubsdad 2010-09-10 01:45:28

1

嘗試rtrimws(ws, ::isspace);。另外,就像一個說明一樣,你應該使用反向迭代器。

+1

cctype頭不保證declare :: isspace,只保留std :: isspace。這裏給出的解決方案是脆弱的。 – 2010-09-12 21:45:04

+0

那麼唯一的解決辦法就是不要使用'using namespace std;'。 – Fozi 2010-09-13 14:13:26

+0

在函數範圍之外,應該避免使用「使用名稱空間標準」。 – 2010-10-24 11:11:24