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