I am following the book C++ Cookbook from O'Reilly and I try one of the examples, here is the code:
#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, is开发者_开发百科wspace);
}
int main(){
string s = "zing ";
wstring ws = L"zonh ";
rtrimws(s);
rtrimws(ws);
cout << s << "|\n";
wcout << ws << "|\n";
}
When I try to compile it, I get the following error
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
and I don't understand what's wrong. If I don't use the char version (string) but the wchar_t version only, everything runs smooth.
By the way, I am using g++ 4.4.3 in an ubuntu machine 64 bits
isspace
is also a template in C++ which accepts a templated character and also a locale with which it uses the facet std::ctype<T>
to classify the given character (so it can't make up its mind what version to take, and as such ignores the template).
Try specifying that you mean the C compatibility version: static_cast<int(*)(int)>(isspace)
. The differences between the compilers could come from the inconsistent handling of deduction from an overloaded function name among the compilers - see this clang PR. See the second case in Faisal's first set of testcases for an analogous case.
Someone pointed out on IRC that this code would call isspace
using a char
- but isspace
takes int
and requires the value given to be in the range of unsigned char
values or EOF
. Now in case that char
is signed on your PC and stores a negative non-EOF value, this will yield to undefined behavior.
I recommend to do it like @Kirill says in a comment and just use the templated std::isspace
- then you can get rid of the function object argument too.
Try rtrimws(ws, ::isspace);
.
Also, just as a note, you should be using the reverse iterator.
That's because isspace
is a template function in c++. It cannot deduce F
. If you want to use C variant of isspace
you could fully qualify its name as follows:
void rtrimws(string& ws){
rtrimws(ws, ::isspace); // this will use isspace from global namespace
// C++ version belongs to the namespace `std`
}
This is one more good sample why you shouldn't use using namespace std
.
精彩评论