Std :: transform () and toupper (), there is no corresponding function

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

#include <iostream> #include <algorithm> int main() { std::string s="hello"; std::string out; std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper); std::cout << "hello in upper case: " << out << std::endl; } 
Theoretically, it should have worked as one example in Josuttis' book, but it does not compile http://ideone.com/aYnfv .

Why did the GCC complain:

 no matching function for call to 'transform( __gnu_cxx::__normal_iterator<char*, std::basic_string <char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string <char, std::char_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string <char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)' 

Am I missing something? Is this a GCC problem?

+56
c ++ algorithm stl
Aug 20 '11 at 12:53 on
source share
2 answers

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

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

Works: http://ideone.com/XURh7

The reason why your code does not work: there is another overloaded toupper function in the std namespace that causes a problem in resolving the name, since the compiler cannot decide what kind of overload you have in mind when you just go through std::toupper . This is why the compiler says unresolved overloaded function type in the error message, which indicates the presence of overload (s).

So, to help the compiler in the correct overload, you should use std::toupper as

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

That is, the following will 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 for yourself: http://ideone.com/8A6iV

+69
Aug 20 2018-11-12T00:
source share

Problem

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

there is no corresponding function to call transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)

This is a mistake; the interesting part is not that there is no suitable function to call, but why there is no corresponding function.

Why do you pass the reference to the " <unresolved overloaded function type> " <unresolved overloaded function type> as an argument, and GCC prefers an error when called, rather than overload resolution failing.




Explanation

First, you should consider how the C library is inherited in C ++. <ctype.h> has an int toupper(int) function.

C ++ inherits this:

[n3290: 21.7/1]: Tables 74, 75, 76, 77, 78, and 79 describe the headers <cctype> , <cwctype> , <cstring> , <cwchar> , <cstdlib> (character conversions) and <cuchar> respectively.

[n3290: 21.7/2]: contents of these headers should be the same as the headers of the standard library C <ctype.h> , <wctype.h> , <string.h> , <wchar.h> and <stdlib.h> and C Unicode TR header <uchar.h> , respectively [..]

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

But the use of <ctype.h> is deprecated:

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

And the access path to C toupper is through the C ++ <cctype> backward compatibility header. For such headers, the content is moved or copied (depending on your implementation) to the std :

[n3290: 17.6.1.2/4]: [..] However, in the C ++ standard library, declarations (with the exception of names that are defined as macros in C) are within the namespace (3.3.6) of the std namespace. Not indicated. whether these names are declared in the global namespace and then entered into the std namespace using explicit using-declarations (7.3.3).

But the C ++ library also introduces a new locale-specific function template in the <locale> header, which is also called toupper (of course, in the std ):

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

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




disparity

Now the OP of this original question has not run into this problem. It probably didn't have the language version of std::toupper in scope, but again you are not #include <locale> either!

However:

[n3290: 17.6.5.2]: The C ++ header may contain other C ++ headers.

It so happened that either your <iostream> , or your <algorithm> , or the headers included in these headers, or the headers included in these headers (etc.) will lead to the inclusion of <locale> in your implementation.




Decision

There are two workarounds for this.

  • You can provide a conversion clause to force the function pointer to refer to the overload you want to use:

     std::transform( s.begin(), s.end(), std::back_inserter(out), (int (*)(int))std::toupper // specific overload requested ); 
  • You can 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, remember that regardless of whether this function is available in <cctype> , it is not specified ( [17.6.1.2/4] ), and the use of <ctype.h> is deprecated ( [C.3.1/1] ).

    So this is not the option I would recommend.




( Note: I despise angle brackets as if they were part of the heading names - they are part of the #include syntax, not the heading names - but I did it here for consistency with FDIS quotes, and frankly, this is clearer ... )

+45
Aug 20 2018-11-11T00:
source share



All Articles