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

No instance of function template remove_if matches argument list

本文关键字:参数 列表 if 函数模板 实例 remove      更新时间:2023-10-16

我正在尝试从字符串中删除空格

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:parsertryparsertrycalc.cpp 18

完整来源

为什么?一段简单的代码

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;
}

验证函数是否有效?

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

不要质疑智能感知,有时最好忽略它。解析器或数据库以某种方式搞砸了,因此它不再正常工作。通常,重新启动将解决问题。

如果你真的想知道代码是否格式不正确,那么,只需按 F7 进行编译。

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

智能感知使用自己的规则,并不总是可靠的。

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

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

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

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

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

为什么typedef

  1. 它使代码更容易适应以下情况 你已经有这样的typedef,这并不少见;

  2. 它使代码更清晰;和

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

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

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

"警告

C4800:"int":强制值为布尔值"真"或"假"(性能警告)">

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

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

嗯,首先,旧的 Cisspace函数是问题中使用的函数,所以这就是这个答案中讨论的函数。我专注于讨论如何不错误地执行此操作,即如何避免未定义的行为。讨论如何正确地做到这一点会把它带到一个完全不同的水平。

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

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

什么是isspace? 取决于包含标头和编译器 您正在使用,您的代码甚至可能无法编译。 (我不 了解智能感知,但它可能正在查看所有 标准标头,并看到歧义。

标准中有两个isspace功能,一个是 模板。 将函数模板传递给另一个函数的模板参数 函数模板没有为编译器提供足够的信息 为了能够进行模板参数推导:为了解决isspace的重载,它必须知道预期的类型remove_if,它只有在模板参数推导才知道 成功。 并且要对remove_if进行模板参数推导,它具有 要知道参数的类型,这意味着isspace的类型, 只有当它能够解决过载问题时,它才会知道 它。

(我真的很惊讶你的一点代码编译:你 显然包括<iostream>,通常,<iostream>将包括<locale>,这将引入函数模板isspace

当然,函数模板isspace必须用两个调用 参数,所以如果它被选中,remove_if的实例化 不会编译(但编译器不会尝试实例化remove_if直到它选择了函数)。 而isspace如果传递char<ctype.h>将导致未定义的行为,因此您 不能使用它。 通常的解决方案是创建一组谓词 工具箱中的对象,然后使用它们。 如下所示 如果您只关心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 是微不足道的,这样你就可以得到完整的 set,我发现添加一个IsNot模板也很有用。 它 简单,它避免了所有周围的问题。