简体   繁体   中英

C++ count_if function - couldn't infer template

I'm trying to use C++'s count_if function to see how many hex digits are in a std::string . When I try the following:

string s = "123abc";
cout << count_if(s.begin(), s.end(), isxdigit) << endl;

I get the following error:

count.cpp:14:13: error: no matching function for call to 'count_if'
    cout << count_if(s.begin(), s.end(), isxdigit) << endl;
            ^~~~~~~~
/usr/include/c++/4.2.1/bits/stl_algo.h:448:5: note: candidate template ignored: couldn't infer
  template argument '_Predicate'
count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred)

However, when I use ::isxdigit , the program compiles and runs. I know prepending the :: has something to do with using the isxdigit in the global scope, but I'm not sure why it helps in this case. I also think it has something to do with C++ locales, but I'm not too familiar with them.

Thanks!

There is a function int isxdigit(int) in the C Standard Library (header <ctype.h> , C++ equivalent header <cctype> ). This can be used unambiguously in count_if .

If you include <ctype.h> , this function ends up in the global namespace. If you include <cctype> , it's guaranteed to be put in namespace std ; but as it's a C-library function, your C++ Standard Library (implementation) is allowed to put it into the global namespace as well.

On the other hand, there is a function template isxdigit in the C++ Standard Library (header <locale> ). This is only put into namespace std .


The reason why you get this error is because you probably have a using namespace std; somewhere, or otherwise make std::isxdigit from <locale> visible. Then, the name isxdigit refers to a set of overloaded functions. As there are multiple candidates, and count_if accepts many of them, the compiler cannot now which overload you meant.

You can specify which overload was meant, for example, by using static_cast<int(*)(int)>(&isxdigit) .


When you use ::isxdigit , only one function is found, so the compiler knows its type and can deduce the template parameter.


A more useful solution than manually choosing the overload is to use a function object with a generic function call operator:

struct Isxdigit
{
    template<class T>
    bool operator()(T const& p) const
    {
        using std::isxdigit;
        return isxdigit(p);
    }
};

int main()
{
    string s = "123abc";
    cout << count_if(s.begin(), s.end(), Isxdigit()) << endl;
}

This automatically selects the proper overload.

In C++1y, you could use generic lambdas:

int main()
{
    string s = "123abc";
    cout << count_if(s.begin(), s.end(), [](auto p){ return isxdigit(p); })
         << endl;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM