71

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

#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'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<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 here? Is it GCC related problem?

Community
  • 1
  • 1
Stack Overeem
  • 835
  • 1
  • 7
  • 5

3 Answers3

85

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

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • This indeed works, but why? `toupper` is also in the `std` namespace (via ``). – Oliver Charlesworth Aug 20 '11 at 13:01
  • @Oli: As I said, there is another overload which is causing the problem. Also, `toupper` also exists in the global namespace (atleast in GCC version). – Nawaz Aug 20 '11 at 13:05
  • @Nawaz: This doesn't sound like an overload ambiguity (`std::toupper` and `::toupper` are completely distinct). It just sounds like the prototypes differ. – Oliver Charlesworth Aug 20 '11 at 13:06
  • @Tomalak: The error does say `unresolved overloaded function type` which implies there is an overload. – Nawaz Aug 20 '11 at 13:07
  • @Nawaz: Oh, I missed that. You're absolutely right. However, I believe your answer's reasoning is wrong; `::toupper` is not conflicting with `std::toupper`; rather, `::toupper` doesn't have any overloads of itself to conflict with, whereas `std::toupper` does. – Lightness Races in Orbit Aug 20 '11 at 13:12
  • 2
    @Tomalak: That is what I said *"..overloaded function toupper in the namespace std"* which means `std::toupper` has overload. – Nawaz Aug 20 '11 at 13:16
  • @Nawaz: What overloads are there? In GCC 4.1.2, `` simply has `namespace std { ... using ::toupper; }`. – Oliver Charlesworth Aug 20 '11 at 13:19
  • 2
    @Oli: `` defines `template charT toupper(charT c, const locale& loc)` – Mike Seymour Aug 20 '11 at 13:27
  • @Oli Charlesworth: There's an [overload](http://msdn.microsoft.com/en-us/library/2fk4ystc%28v=VS.100%29.aspx) that takes a locale. – Praetorian Aug 20 '11 at 13:27
  • 5
    If you do use `::toupper`, it would be best to include the C header (``) to make sure it's in the global namespace. Then you'll be relying on deprecated but well-specified behaviour, not unspecified behaviour. – Mike Seymour Aug 20 '11 at 13:29
  • 2
    Sorry, but the opening to this answer ("Just use toupper instead of std::toupper") is incomplete. If the OP uses `using namespace std` then [it ceases to be a viable workaround](http://ideone.com/GiJw2) (not to mention that you're either using deprecated or unspecified behaviour even when it _does_ work). – Lightness Races in Orbit Aug 20 '11 at 15:11
  • @Tomalak: That is true, but 1) I never said `Just use toupper instead of `std::toupper` is a complete answer, and that is why I added the explanation and what to do with `std::toupper` to make it work. 2) If you read the post incompletely, you will get an incomplete answer. 3) Also, the bigger problem is in `using namespace std` than in `toupper`. How many of us recommend this in the first place? 4) I've already seen him using `std::transform` and `std::toupper` - the fully qualified names, I can assume that he wouldn't add `using namespace std`.[contd.] – Nawaz Aug 20 '11 at 15:59
  • @Tomalak: [contd]. 5) But to make you happy, I'm going to add `::` to `toupper`. :-) – Nawaz Aug 20 '11 at 16:01
  • @Nawaz: Better. :) I think it was misleading before; there was no indication at all that the latter workaround was superior to the former. And assuming that he'll _never_ have `std::toupper` in scope is a bit of a leap, and makes for a non-robust answer. :) – Lightness Races in Orbit Aug 20 '11 at 16:03
  • I think it's the use of the word "just" that implies excess simplicity, and that the sentence may be taken on its own without the rest of the answer. "Just" means that there are no further caveats. – Lightness Races in Orbit Sep 20 '11 at 12:14
51

Problem

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

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>)

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 "<unresolved overloaded function type>" 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++. <ctype.h> has a function int toupper(int).

C++ inherits this:

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

[n3290: 21.7/2]: The contents of these headers shall be the same as the Standard C Library headers <ctype.h>, <wctype.h>, <string.h>, <wchar.h>, and <stdlib.h> and the C Unicode TR header <uchar.h>, 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 <ctype.h> 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 <cctype>. 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 <locale>, that's also called toupper (of course, in namespace 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 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 <locale> either!

However:

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

So it just so happens that either your <iostream> or your <algorithm>, or headers that those headers include, or headers that those headers include (etc), lead to the inclusion of <locale> 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 <cctype> is available is unspecified ([17.6.1.2/4]), and using <ctype.h> 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...)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 7
    **Note:** This is all slightly silly, because `std::transform` is, itself, looking for a specific function signature so in theory the compiler could deduce solution 1 _for you_. But, well, it's complicated; and welcome to C++. – Lightness Races in Orbit Aug 20 '11 at 13:40
  • Great exposition man, I need some time to understand many of the points mentioned. Thanks a lot! – Stack Overeem Aug 20 '11 at 13:46
  • @Stack: No problem! It took me some time to collate them. :P – Lightness Races in Orbit Aug 20 '11 at 13:47
  • 1
    a bit late to the party, but I still think the compiler should AT LEAST list the ambigous options. – Vargas Aug 14 '15 at 13:06
  • 1
    @Vargas: It can't! The options don't exist (or there are infinite options, depending on how you look at it) until `std::transform` (a template) has been instantiated, which cannot happen until the type of the final argument (the functor) is known. Chicken vs egg :) – Lightness Races in Orbit Aug 14 '15 at 13:19
  • @BarryTheHatchet Interestingly, it seems that Visual C++ _is_ able to deduce solution 1 for you, at least in my experience. I was attempting to troubleshoot a runtime error in a different environment, so I copied the relevant part of the project into an online Linux GCC compiler, and it wouldn't even compile because GCC couldn't resolve the overload. The code compiles with both Visual Studio 2010 and VS2015 WebCompiler, but not with GCC. This suggests to me that the overloads are only visible in MSVC if you explicitly include the header, while they're always visible in GCC. – Justin Time - Reinstate Monica Mar 07 '16 at 22:07
  • That, or MSVC is just better at deducing the right one, but I'm not sure if the way it does so is standard-compliant. – Justin Time - Reinstate Monica Mar 07 '16 at 22:13
  • 1
    @JustinTime: Don't forget that standard headers are allowed to include other standard headers and it's unspecified which (if any) those will be, under any given implementation. – Lightness Races in Orbit Mar 07 '16 at 22:27
  • 1
    True, forgot about that. It's possible that GCC includes `` behind the scenes when you include `` and/or ``, and VS doesn't. Alternatively, it's possible that one of the other headers (most likely ``) includes `` behind the scenes. – Justin Time - Reinstate Monica Mar 07 '16 at 23:36
  • 2
    ...And it seems that's the issue, or at least a significant part of it. To determine if this was the reason for the difference in behaviour, I wrote a simple program that reads a string, transforms it with `toupper()`, & outputs the result. It includes ``, ``, ``, ``, & ``. It seems that, interestingly enough, MSVC 2010 is able to correctly deduce which version of `toupper()` you want, while later versions (or at least 2015) can't. MSVC 2015 is fine as long as you don't explicitly include ``, but it can't resolve the overload if you do. – Justin Time - Reinstate Monica Mar 07 '16 at 23:37
  • This suggests that MSVC 2010 is exhibiting abnormal behaviour, while GCC and MSVC 2015 are more in line with what one would expect. It also suggests that GCC includes `` behind the scenes, while MSVC does not. Guess that answers that, then. – Justin Time - Reinstate Monica Mar 07 '16 at 23:39
0
std::transform(s.begin(), s.end(), s.begin(), 
std::bind(&std::toupper<char>, std::placeholders::_1, std::locale()));

If you use vc toolchain,please include locale