我正在尝试从字符串
中删除空格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
为什么?一段简单的代码
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;
}
验证功能是否有效?
有趣的是,尽管如此,它运行给出了正确的结果。
答案 0 :(得分:1)
不要质疑Intellisense,有时最好忽略它。解析器或数据库以某种方式搞砸了,所以它不再正常工作。通常,重启会解决问题。
如果您真的想知道代码是否格式错误,那么只需点击F7即可编译。
答案 1 :(得分:0)
使用Visual C ++ 11.0(Visual Studio 2012附带的编译器)编译源代码时甚至没有警告。
Intellisense使用自己的规则并不总是可靠的。
也就是说,对于除原始7位ASCII之外的所有字符集,您对isspace
的使用是未定义行为。这意味着你从中获得了大量赞成的答案,这只是balderdash(这不应该令人惊讶)。您需要将参数转换为(C库)isspace
到unsigned 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
?
它使代码更容易适应
你已经有了typedef
,这并不罕见;
它使代码更清晰;以及
它避免了C语法转换,从而避免了通过正则表达式或其他模式匹配搜索此类错误时的误报。
但是,为什么!!
(否定运算符的双重应用)?考虑到从int
到bool
的自动隐式转换?而且,如果绝对认为转换应该是明确的,那么它不应该是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
模板也很有用。它的
简单,它避免了所有的周围问题。