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
-
использовать лямбда-выражение:
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; })
- используйте явные типы шаблонов (вам также нужно написать тип итератора):
std::count_if<std::string::const_iterator, int(*)(int)>(s.begin(), s.end(), std::isdigit)