C++使用带字符串的标准算法,带isdigit的count_if,函数转换

C++ using standard algorithms with strings, count_if with isdigit, function cast

本文关键字:count if 转换 函数 isdigit 算法 字符串 标准 C++      更新时间:2023-10-16

我想用最短的代码方式计算字符串中的所有数字。我试过了:

#include <string>
#include <algorithm>
unsigned countNumbers(const std::string s) {
    return count_if(s.begin(), s.end(), isdigit);
}

错误消息为:

a.cc: In function ‘unsigned int countNumbers(std::string)’:
a.cc:5:45: error: no matching function for call to ‘count_if(std::basic_string<char>::const_iterator, std::basic_string<char>::const_iterator, <unresolved overloaded function type>)’
a.cc:5:45: note: candidate is:
/usr/include/c++/4.6/bits/stl_algo.h:4607:5: note: template<class _IIter, class _Predicate> typename std::iterator_traits<_InputIterator>::difference_type std::count_if(_IIter, _IIter, _Predicate)

我知道count_if((想要这样的函数:bool(*f((char(;作为第三个参数,所以我尝试转换函数:

unsigned countNumbers(const std::string s) {
    return count_if(s.begin(), s.end(), reinterpret_cast<bool (*)( char )>(isdigit));
}

错误消息为:

a.cc: In function ‘unsigned int countNumbers(std::string)’:
a.cc:5:80: error: overloaded function with no contextual type information

我还尝试了一个更长的版本,它给出了相同的编译错误:

unsigned countNumbers(const std::string s) {
    typedef bool ( * f_ptr )( char );
    f_ptr ptr = reinterpret_cast<f_ptr>(isdigit);
    return count_if(s.begin(), s.end(), ptr);
}

我想避免的解决方案是创建一个适配器函数:

#include <string>
#include <algorithm>
bool is_digit(char c) {
    return isdigit(c);
}
unsigned countNumbers(const std::string s) {
    return count_if(s.begin(), s.end(), is_digit);
}

我的问题是,在不创建适配器函数和不使用lambda表达式的情况下,如何在std::algorithm的函数中使用函数int(*f((int(

当我知道如何解决问题时,我会解决更多的问题,例如:

  • 检查字符串是否可打印:find_if_not(s.begin((,s.end((,isprint(
  • 检查字符串是否包含",.!?…":find_if(s.begin((,s.end((,ispunct(还有更多

我只想知道如何在标准C++中有更多的字符串可能性,这要归功于std::算法我在互联网上搜索了很长时间,我发现了类似的问题,但我没有找到解决方案

您可以使用静态强制转换来解析函数。或者,如果这是你想做的事情,你可以使用一个模板来解决它:

#include <string>
#include <cctype>
#include <algorithm>
unsigned count(const std::string& s) {
  return std::count_if(s.begin(), s.end(), static_cast<int(*)(int)>(std::isdigit));
}
template <int(*Pred)(int)> 
unsigned foo(const std::string& s) {
  return std::count_if(s.begin(), s.end(), Pred);
}
int main() {
  count("");
  foo<std::isdigit>("");
  foo<std::isprint>("");
}

static_cast是解决歧义的"常用"方法——它总是做你期望的事情,并且可以成为更大表达式的一部分。

使用函数指针解析类型:

unsigned countNumbers(const std::string s) {
    int (*isdigit)(int) = std::isdigit;
    return count_if(s.begin(), s.end(), isdigit);
}

不要忘记包括<cctype>。(演示(

我发现以下也有效:

    #include <ctype.h>
    count_if(s.begin(), s.end(), ::isdigit); //explicitly select the C version of isdigit 

但我必须弄清楚,只有当C版本被定义为函数时,它才有效而不是宏

因此,std::isdigit的staticcast可能是平台中最好的可移植解决方案。

我将给出另外两个解决方案来修复<locale> std::isdigit 的模糊性

  1. 使用lambda表达式:

    std::count_if(s.begin(), s.end(), [](char c){ return std::isdigit(c); })

或显式铸造:

std::count_if(s.begin(), s.end(), [](char c){ return std::isdigit(static_cast<int>(c)) != 0; })
  1. 使用显式模板类型(您还需要编写迭代器类型(:

std::count_if<std::string::const_iterator, int(*)(int)>(s.begin(), s.end(), std::isdigit)