Here’s the code to find whether a string contains only digits:
#include <iostream> //see below
#include <string>
#include <cctype>
int main() {
std::string s("123");
std::all_of(s.begin(), s.end(), std::isdigit); //error!
}
But the code doesn’t compile, with the following errors:
error: no matching function for call to 'all_of'
note: candidate template ignored: couldn't infer template argument '_Predicate'
all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred)
When I replace std::isdigit with isdigit, the code compiles without errors.
#include <iostream> //see below
#include <string>
#include <cctype>
int main() {
std::string s("123");
std::all_of(s.begin(), s.end(), isdigit); //OK
}
So what’s the differences between isdigit and std::isdigit? I know that isdigit is inherited from the C language header ctype.h, and that std::isdigit is a wrapper defined in C++ header cctype, so essentially they should be the same. Am I getting anything wrong?
I tried the above on both Apple clang and linux g++, and got similar errors.
What’s more confusing, when I remove the #include <iostream> line on Apple clang, the code compiles again:
// iostream not included
#include <string>
#include <cctype>
int main() {
std::string s("123");
std::all_of(s.begin(), s.end(), std::isdigit); //OK
}
But removing #include <iostream> doesn’t work on gcc.
Since both clang and gcc generated the same error, it’s unlikely to be a bug of compilers. I also tried different C++ standards (11, 14, 17, 20). Am I getting anything wrong here?
>Solution :
In C++, you are not allowed to take the address of most standard library functions:
https://en.cppreference.com/w/cpp/language/extending_std#Addressing_restriction
The behavior of a C++ program is unspecified (possibly ill-formed) if it explicitly or implicitly attempts to form a pointer, reference (for free functions and static member functions) or pointer-to-member (for non-static member functions) to a standard library function or an instantiation of a standard library function template, unless it is designated an addressable function
std::isdigit() is not an addressable standard library function, so you can’t use it directly as an algorithm predicate.
That begin said, even if you could pass std::isdigit() directly as a predicate, doing so would risk undefined behavior:
https://en.cppreference.com/w/cpp/string/byte/isdigit
Like all other functions from
<cctype>, the behavior ofstd::isdigitis undefined if the argument’s value is neither representable asunsigned charnor equal toEOF. To use these functions safely with plainchars (orsigned chars), the argument should first be converted tounsigned char:bool my_isdigit(char ch) { return std::isdigit(static_cast<unsigned char>(ch)); }Similarly, they should not be directly used with standard algorithms when the iterator’s value type is
charorsigned char. Instead, convert the value tounsigned charfirst:int count_digits(const std::string& s) { return std::count_if(s.begin(), s.end(), // static_cast<int(*)(int)>(std::isdigit) // wrong // [](int c){ return std::isdigit(c); } // wrong // [](char c){ return std::isdigit(c); } // wrong [](unsigned char c){ return std::isdigit(c); } // correct ); }
As such, since you need to convert each char to unsigned char and back, you should call std::isdigit() inside of a lambda that is used as the predicate for std::all_of(), eg:
std::all_of(s.begin(), s.end(),
[](unsigned char ch){ return std::isdigit(ch); }
);