std::transform() and toupper(), no matching function

匿名 (未验证) 提交于 2019-12-03 08:51:18

问题:

I tried the code from this question C++ std::transform() and toupper() ..why does this fail?

#include  #include   int main() {   std::string s="hello";   std::string out;   std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper);   std::cout 

Theoretically it should've worked as it's one of the examples in Josuttis' book, but it doesn't compile http://ideone.com/aYnfv.

Why did GCC complain:

no matching function for call to ‘transform(     __gnu_cxx::__normal_iterator, std::allocator > >,      __gnu_cxx::__normal_iterator, std::allocator > >,      std::back_insert_iterator<:basic_string std::char_traits="">, std::allocator > >,     )’ 

Am I missing something here? Is it GCC related problem?

回答1:

Just use ::toupper instead of std::toupper. That is, toupper defined in the global namespace, instead of the one defined in std namespace.

std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper); 

Its working : http://ideone.com/XURh7

Reason why your code is not working : there is another overloaded function toupper in the namespace std which is causing problem when resolving the name, because compiler is unable to decide which overload you're referring to, when you simply pass std::toupper. That is why the compiler is saying unresolved overloaded function type in the error message, which indicates the presence of overload(s).

So to help the compiler in resolving to the correct overload, you've to cast std::toupper as

(int (*)(int))std::toupper 

That is, the following would work:

//see the last argument, how it is casted to appropriate type std::transform(s.begin(), s.end(), std::back_inserter(out),(int (*)(int))std::toupper); 

Check it out yourself: http://ideone.com/8A6iV



回答2:

Problem

std::transform(     s.begin(),     s.end(),     std::back_inserter(out),     std::toupper ); 

no matching function for call to ‘transform(__gnu_cxx::__normal_iterator, std::allocator > >, __gnu_cxx::__normal_iterator, std::allocator > >, std::back_insert_iterator<:basic_string std::char_traits="">, std::allocator > >, )

This is a misleading error; the interesting part is not that there's "no matching function" for the call, but why there's no matching function.

The why is that you're passing a function reference of an "" as an argument, and GCC prefers to error on the call rather than on this overload resolution failure.


Explanation

First, you should consider how the C library is inherited in C++. has a function int toupper(int).

C++ inherits this:

[n3290: 21.7/1]: Tables 74, 75, 76, 77, 78, and 79 describe headers , , , , (character conversions), and , respectively.

[n3290: 21.7/2]: The contents of these headers shall be the same as the Standard C Library headers , , , , and and the C Unicode TR header , respectively [..]

[n3290: 17.6.1.2/6]:Names that are defined as functions in C shall be defined as functions in the C++ standard library.

But using is deprecated:

[n3290: C.3.1/1]: For compatibility with the Standard C library, the C++ standard library provides the 18 C headers (D.5), but their use is deprecated in C++.

And the way to access the C toupper is through the C++ backwards-compatibility header . For such headers, the contents are either moved or copied (depending on your implementation) into the std namespace:

[n3290: 17.6.1.2/4]: [..] In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).

But the C++ library also introduces a new, locale-specific function template in header , that's also called toupper (of course, in namespace std):

[n3290: 22.2]: [..] template charT toupper(charT c, const locale& loc); [..]

So, when you use std::toupper, there are two overloads to choose from. Since you didn't tell GCC which function you wish to use, the overload cannot be resolved and your call to std::transform cannot be completed.


Disparity

Now, the OP of that original question did not run into this problem. He likely did not have the locale version of std::toupper in scope, but then again you didn't #include either!

However:

[n3290: 17.6.5.2]: A C++ header may include other C++ headers.

So it just so happens that either your or your , or headers that those headers include, or headers that those headers include (etc), lead to the inclusion of on your implementation.


Solution

There are two workarounds to this.

  1. You may provide a conversion clause to coerce the function pointer into referring to the overload that you wish to use:

    std::transform(    s.begin(),    s.end(),    std::back_inserter(out),    (int (*)(int))std::toupper  // specific overload requested ); 
  2. You may remove the locale version from the overload set by explicitly using the global toupper:

    std::transform(    s.begin(),    s.end(),    std::back_inserter(out),    ::toupper                  // global scope ); 

    However, recall that whether or not this function in is available is unspecified ([17.6.1.2/4]), and using is deprecated ([C.3.1/1]).

    Thus, this is not the option that I would recommend.


(Note: I despise writing angle brackets as if they were part of header names ― they are part of #include syntax, not header names ― but I've done it here for consistency with the FDIS quotes; and, to be honest, it is clearer...)



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!