简体   繁体   English

C ++ count_if函数 - 无法推断模板

[英]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 . 我正在尝试使用C ++的count_if函数来查看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. 但是,当我使用::isxdigit ,程序会编译并运行。 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. 我知道在全局范围内使用isxdigit可以预先设置::但是我不确定为什么它在这种情况下会有所帮助。 I also think it has something to do with C++ locales, but I'm not too familiar with them. 我也认为它与C ++语言环境有关,但我对它们并不太熟悉。

Thanks! 谢谢!

There is a function int isxdigit(int) in the C Standard Library (header <ctype.h> , C++ equivalent header <cctype> ). C标准库中有一个函数int isxdigit(int) (头文件<ctype.h> ,C ++等效头文件<cctype> )。 This can be used unambiguously in count_if . 这可以在count_if明确使用。

If you include <ctype.h> , this function ends up in the global namespace. 如果包含<ctype.h> ,则此函数最终在全局命名空间中。 If you include <cctype> , it's guaranteed to be put in namespace std ; 如果包含<cctype> ,则保证将其放在命名空间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. 但由于它是一个C库函数,因此允许您的C ++标准库(实现)将其放入全局命名空间。

On the other hand, there is a function template isxdigit in the C++ Standard Library (header <locale> ). 另一方面,C ++标准库(header <locale> )中有一个函数模板 isxdigit This is only put into namespace std . 这只是放在命名空间std


The reason why you get this error is because you probably have a using namespace std; 你得到这个错误的原因是因为你可能有一个using namespace std; somewhere, or otherwise make std::isxdigit from <locale> visible. 在某处,或以其他方式使<locale> std::isxdigit可见。 Then, the name isxdigit refers to a set of overloaded functions. 然后,名称isxdigit引用一组重载函数。 As there are multiple candidates, and count_if accepts many of them, the compiler cannot now which overload you meant. 由于有多个候选者,并且count_if接受了许多候选者,因此编译器现在无法实现哪种重载。

You can specify which overload was meant, for example, by using static_cast<int(*)(int)>(&isxdigit) . 您可以指定使用哪个重载,例如,使用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. 当您使用::isxdigit ,只找到一个函数,因此编译器知道其类型并可以推导出模板参数。


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: 在C ++ 1y中,您可以使用泛型lambda:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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