Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Differences between `isdigit` and `std::isdigit`

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#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 of std::isdigit is undefined if the argument’s value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned 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 char or signed char. Instead, convert the value to unsigned char first:

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); }
);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading