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

I want to read all the numbers in a string in a short way of code. I tried like this:

#include <string>
#include <algorithm>

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

Error message:

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)

I know that the count_if () function wants: bool (* f) (char); as the third argument, so I tried using the function:

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

Error message:

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

I tried an even longer version that gives the same compilation error:

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

The solution I want to avoid is to create a function that will be an adapter:

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

My question is: how can I use int (* f) (int) functions in std :: algorithms that want bool (* f) (int) without creating adaptation functions and without using lambda expressions?

I have more problems to be solved when I learn how to solve the problem, for example:

  • Check if the string is available: find_if_not (s.begin (), s.end (), isprint)
  • , ",.!?...": find_if (s.begin(), s.end(), ispunct) ...

, ++ std:: algorithmms , ,

+5
4

, . , , , :

#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 - "" - , , .

+3

:

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

<cctype>. ()

+3

I found the following works:

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

but I have to understand that it only works if version C is defined as a function and not a macro

So static_cast from std :: isdigit may be the best portable solution among platforms.

+1
source

I will give 2 more solutions to correct the ambiguity with <locale> std::isdigit

  • Use lambda expression:

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

or with explicit casting:

std::count_if(s.begin(), s.end(), [](char c){ return std::isdigit(static_cast<int>(c)) != 0; })
  1. Use explicit template types (you also need to write an iterator type):

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

0
source

All Articles