没有函数模板remove_if的实例匹配参数列表

时间:2012-10-25 13:21:09

标签: c++

我正在尝试从字符串

中删除空格
line.erase(remove_if(line.begin(), line.end(), isspace), line.end()); 

但Visual Studio 2010(C ++ Express)告诉我

1   IntelliSense: no instance of function template "std::remove_if" matches the argument list   d:\parsertry\parsertry\calc.cpp 18

Full Source

为什么?一段简单的代码

int main() {
    string line = "hello world   111    222";
    line.erase(remove_if(line.begin(), line.end(), isspace), line.end());
    cout << line << endl;

    getchar();

    return 0;
}

验证功能是否有效?

有趣的是,尽管如此,它运行给出了正确的结果。

3 个答案:

答案 0 :(得分:1)

不要质疑Intellisense,有时最好忽略它。解析器或数据库以某种方式搞砸了,所以它不再正常工作。通常,重启会解决问题。

如果您真的想知道代码是否格式错误,那么只需点击F7即可编译。

答案 1 :(得分:0)

使用Visual C ++ 11.0(Visual Studio 2012附带的编译器)编译源代码时甚至没有警告。

Intellisense使用自己的规则并不总是可靠的。

也就是说,对于除原始7位ASCII之外的所有字符集,您对isspace的使用是未定义行为。这意味着你从中获得了大量赞成的答案,这只是balderdash(这不应该令人惊讶)。您需要将参数转换为(C库)isspaceunsigned char以避免负值和UB。

C99§7.4/ 1 (来自N869草案):

  

标题<ctype.h>声明了几个对测试和映射有用的函数   字符。   在所有情况下,参数都是int,其值应为。{1}}   可表示为unsigned char或等于宏EOF的值。如果   参数有任何其他值,行为未定义。

包装C函数的一种简单方法是

bool isSpace( char const c )
{
    typedef unsigned char UChar;
    return !!::isspace( UChar( c ) );
}

为什么typedef

  1. 它使代码更容易适应 你已经有了typedef,这并不罕见;

  2. 它使代码更清晰;以及

  3. 它避免了C语法转换,从而避免了通过正则表达式或其他模式匹配搜索此类错误时的误报。

  4. 但是,为什么!!(否定运算符的双重应用)?考虑到从intbool的自动隐式转换?而且,如果绝对认为转换应该是明确的,那么它不应该是static_cast,而不是!!吗?

    好吧,!!避免了来自Visual C ++编译器的愚蠢警告,

      

    “警告C4800:'int':强制值为bool'true'或'false'(性能警告)”

    并且static_cast不会停止该警告。解决该警告是一种很好的做法,并且由于Visual C ++是最常用系统(即Windows)上的主要C ++编译器,因此在所有可移植的代码中更好地执行此操作。

    哦,好吧,但是,既然函数必须被包装,那么...当isspace标题提供更灵活时,为什么要使用旧的C libary <locale>(单个参数)函数C ++(两个参数)isspace函数?

    嗯,首先,旧的C isspace函数是在问题中使用的函数,所以这是本答案中讨论的函数。我专注于讨论如何不正确地做到这一点,即如何避免未定义的行为。讨论如何做到正确将它带到一个完全不同的层面。

    但是在实践中,同名的C ++级别函数可以被认为是破坏的,因为直到最近才使用g ++编译器(甚至可能使用g ++ 4.7.2,我最近没有检查过)只有在Windows中,C语言环境机制起作用,而C ++级别机制则没有。它可能已被修复,因为g ++现在支持宽流,我不知道。无论如何,C库isspace功能,除了在实践中更具可移植性并且通常在Windows中工作外,还更简单,我相信,更多高效(虽然为了效率,如果认为重要,应该总是测量!)。

    感谢James Kanze在评论中提出(基本上)上述问题。

答案 2 :(得分:0)

什么是isspace?取决于包含标头和编译器 你正在使用,你的代码可能甚至不会编译。 (我不 了解IntelliSense,但有可能它正在全力以赴 标准标题,并看到歧义。)

标准中有两个isspace函数,一个是a 模板。将函数模板传递给另一个的模板参数 函数模板没有给编译器足够的信息 能够做模板参数演绎:为了解决问题 isspace的重载,它必须知道预期的类型 remove_if,它只知道模板参数扣除之后的 成功了。并且在remove_if上进行模板参数推导,它有 知道参数的类型,这意味着isspace的类型, 它只有在能够解决过载后才能知道 它

(我真的很惊讶你的一点代码编译:你 显然包括<iostream>,通常<iostream>会包含 <locale>,它将引入功能模板isspace。)

当然,函数模板isspace必须用两个调用 参数,所以如果它被选中,remove_if的实例化 不会编译(但编译器不会尝试实例化 remove_if直到它选择了一个函数)。而且isspace在 如果传递<ctype.h>char将导致未定义的行为,所以你 不能用它。通常的解决方案是创建一组谓词 工具箱的对象,并使用它们。像下面这样的东西 如果你只关心char

,那应该有用
template <std::ctype<char>::mask m>
class Is : public std::unary_function<char, bool>
{
    std::locale myLocale;  //  To ensure lifetime of following...
    std::ctype<char> const* myCType;
public:
    Is( std::locale const& loc = std::locale() )
        : myLocale( loc )
        , myCType( &std::use_facet<std::ctype<char> >( myLocale ) )
    {
    }

    bool operator()( char ch ) const
    {
        return myCType->is( m, ch );
    }
};
typedef Is<std::ctype_base::space> IsSpace;

添加额外的typedef是非常简单的,所以你可以得到完整的 设置,我发现添加IsNot模板也很有用。它的 简单,它避免了所有的周围问题。