重载函数不编译

时间:2010-09-09 19:16:20

标签: c++ templates stl

我正在关注O'Reilly的C ++ Cookbook一书,我尝试了其中一个例子,这里是代码:

#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

我不明白什么是错的。如果我不使用char版本(字符串)但仅使用wchar_t版本,则一切都运行顺畅。

顺便说一句,我在64位的ubuntu机器上使用g ++ 4.4.3

3 个答案:

答案 0 :(得分:1)

isspace也是C ++中的一个模板,它接受一个模板化的角色以及一个区域设置,它使用facet std::ctype<T>来对给定的角色进行分类(所以它无法决定什么要采取的版本,因此忽略模板)。

尝试指定您指的是C兼容版本:static_cast<int(*)(int)>(isspace)。编译器之间的差异可能来自于编译器中重载函数名称的不一致处理 - 请参阅此clang PR。请参阅Faisal针对类似案例的第一组测试案例中的第二个案例。


有人在IRC上指出,此代码会使用isspace调用char,但isspace需要int,并且要求给定的值在unsigned char范围内{1}}值或EOF。现在,如果在您的PC上签名char并存储负的非EOF值,则会产生未定义的行为。

我建议像@Kirill在评论中说的那样,只使用模板std::isspace - 然后你也可以摆脱函数对象参数。

答案 1 :(得分:1)

尝试rtrimws(ws, ::isspace);

另外,请注意,您应该使用反向迭代器。

答案 2 :(得分:0)

那是因为isspace是c ++中的模板函数。它无法推断F。如果您想使用isspace的C变体,您可以完全限定其名称,如下所示:

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

这是一个更好的示例,为什么你不应该使用using namespace std