【问题标题】:STL generic algorithms - implicit conversion of the ranges element type to the predicates parameter typeSTL 通用算法 - 范围元素类型到谓词参数类型的隐式转换
【发布时间】:2021-11-20 07:00:56
【问题描述】:

假设我想使用erase-remove 习惯用法删除std::string 中的所有标点符号。

但是,让strstd::string 类型,此调用将无法编译

str.erase( std::remove_if(str.begin(), str.end(), std::ispunct), str.end() );

现在我猜,严格来说std::ispunct 可调用参数类型是int,因此与范围元素类型char 不匹配。 但是,由于char 是数字类型,它应该可以转换为int。我正在使用 Lippman 的 C++ Primer 书,其中指出

采用谓词的算法在输入范围内的元素上调用谓词。 [...] 必须可以将元素类型转换为输入范围内的参数类型。

上面的声明中给出了哪个imo。 同样std::ispunct 返回一个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(),
                          [] ( char ch ) { return std::ispunct(ch); }),
            str.end() );

仍然让我感到惊讶的是 lambda 是必要的......

提前致谢!

【问题讨论】:

标签: c++ stl implicit-conversion


【解决方案1】:

考虑以下代码:

#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 的调用。前者可以,后者不行。

error is

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 实际上有两个版本(一个在&lt;locale&gt; 中)。

【讨论】:

  • 对不起,我不明白哪个函数被重载,因此编译器无法解析。 ctype 中只有 one declarationstd::ispunct 函数。在标题 algorithm 中,只有一个带有三个参数的 remove_if 声明,第三个是一元谓词,如您使用函数 foo 的示例所示正确解析。
  • @bsng 我明白你的困惑,因为第二个重载在&lt;locale&gt; (修改了我的答案的结尾以反映这一点)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-24
  • 2020-01-29
  • 1970-01-01
  • 2022-07-29
  • 1970-01-01
相关资源
最近更新 更多