STL 通用算法 - 范围元素类型到谓词参数类型的隐式转换
STL generic algorithms - implicit conversion of the ranges element type to the predicates parameter type
假设我想使用 erase-remove idiom 删除 std::string
中的所有标点符号。
但是,让 str
为 std::string
类型,此调用将无法编译
str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );
现在我想,严格来说 std::ispunct
callables 参数类型是 int
,因此与范围元素类型 char
不匹配。
但是,由于 char
是数字类型,它应该可以转换为 int
。我正在使用 Lippman 的 C++ Primer 书,其中指出
The algorithms that take predicates call the predicate on the elements in the input range. [...] it must be possible to convert the element type to the parameter type in the input range.
上面的语句给出了哪个imo。
还有 std::ispunct
returns 和 int
,因此应该可以用作条件。
那么为什么编译器会抱怨 no matching function for call to 'remove_if'
?
(clang++ -std=c++11 -o main main.cc
)
解决方法是使用 lambda
str.erase( std::remove_if(str.begin(), str.end(),
[] ( unsigned char ch ) { return std::ispunct(ch); }),
str.end() );
仍然让我感到惊讶的是,lambda 是必需的...
提前致谢!
考虑以下代码:
#include <iostream>
#include <algorithm>
#include <functional>
#include <string>
using namespace std;
bool foo(int i) { return true; }
int main() {
string str = string("");
str.erase( std::remove_if(str.begin(), str.end(), foo), str.end() );
str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );
}
这包含一个使用 foo
的调用和一个使用 std::ispunct
的调用。前者可以,后者不行
main.cpp:13:30: error: no matching function for call to 'remove_if(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
13 | str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );)
main.cpp:13:30: error: no matching function for call to 'remove_if(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
13 | str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );
所以问题不在于转换,因为它适用于 foo
。问题是它无法解决您的意思是哪个重载。注意ispunct
(one is in <locale>
).
实际上有两个版本
假设我想使用 erase-remove idiom 删除 std::string
中的所有标点符号。
但是,让 str
为 std::string
类型,此调用将无法编译
str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );
现在我想,严格来说 std::ispunct
callables 参数类型是 int
,因此与范围元素类型 char
不匹配。
但是,由于 char
是数字类型,它应该可以转换为 int
。我正在使用 Lippman 的 C++ Primer 书,其中指出
The algorithms that take predicates call the predicate on the elements in the input range. [...] it must be possible to convert the element type to the parameter type in the input range.
上面的语句给出了哪个imo。
还有 std::ispunct
returns 和 int
,因此应该可以用作条件。
那么为什么编译器会抱怨 no matching function for call to 'remove_if'
?
(clang++ -std=c++11 -o main main.cc
)
解决方法是使用 lambda
str.erase( std::remove_if(str.begin(), str.end(),
[] ( unsigned char ch ) { return std::ispunct(ch); }),
str.end() );
仍然让我感到惊讶的是,lambda 是必需的...
提前致谢!
考虑以下代码:
#include <iostream>
#include <algorithm>
#include <functional>
#include <string>
using namespace std;
bool foo(int i) { return true; }
int main() {
string str = string("");
str.erase( std::remove_if(str.begin(), str.end(), foo), str.end() );
str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );
}
这包含一个使用 foo
的调用和一个使用 std::ispunct
的调用。前者可以,后者不行
main.cpp:13:30: error: no matching function for call to 'remove_if(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
13 | str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );)
main.cpp:13:30: error: no matching function for call to 'remove_if(std::__cxx11::basic_string<char>::iterator, std::__cxx11::basic_string<char>::iterator, <unresolved overloaded function type>)'
13 | str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );
所以问题不在于转换,因为它适用于 foo
。问题是它无法解决您的意思是哪个重载。注意ispunct
(one is in <locale>
).