C++ используя стандартные алгоритмы со строками, count if with isdigit, функция cast

Я хочу подсчитать все числа в строке самым коротким способом кода. Я попробовал так:

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

мой вопрос в том, как я могу использовать функции int(*f)(int) в функциях std::алгоритма, которые хотят bool(*f)(int) без создания адаптерных функций и без использования лямбда-выражений?

у меня есть больше проблем, которые будут решены, когда я узнаю, как решить проблему, например:

  • проверить, если строка печати: find_if_not(С. начать(), С. конец(), isprint)
  • проверьте, если строка содержит ",.!?...": find_if (С. начать(), С. конец(), ispunct) и еще...

Я просто хочу знать, как иметь гораздо больше возможностей строки в стандартном C++ благодаря std:: алгоритмам Я искал в Интернете долгое время, я нашел похожие проблемы, но я не нашел решения

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 - это "обычный" способ разрешения неоднозначны - он всегда делает то, что вы ожидаете, и может быть частью большего выражения.


разрешите тип с помощью указателя функции:

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 определяется как функция а не макрос

таким образом, Ну, static_cast std::isdigit может быть лучшим портативным решением среди платформ.


Я дам 2 других решения, чтобы исправить двусмысленность с <locale> std::isdigit

  1. использовать лямбда-выражение:

    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)