Please help me about std::toupper

Why i using “std::toupper”, the complier shows “error: no matching function for call to ‘transform(std::basic_string::iterator, std::basic_string::iterator, std::basic_string::iterator, )’”

using ::toupper or toupper can run.

codes:

#include <algorithm>
#include <cctype>
#include <iostream>

int main(){
    std::string str("abcdefg");
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
    std::cout << str << '\n';
}

The following code compiles and works for me:

// For std::cout, std::cin
#include <iostream>

// For std::string
#include <string>

// For std::transform
#include <algorithm>

// For std::toupper
#include <cctype>

int main()
{
	std::string string("abcdefg");
	std::transform(string.begin(), string.end(), string.begin(), std::toupper);
	std::cout << string << '\n';
	std::cin.get();
}

If that doesn’t work for you, then I can think of a number of possible reasons:

  • There could be a problem the syntax you were using
  • There could be a problem with your standard library
  • The lack of #include <string> could be causing the problem somehow

Without knowing more about your compiler I can only guess.


I’d like to point out that both your code and the example I gave are semantically incorrect because whether char may be signed.

cppreference explains this in the ‘Notes’ section of std::toupper:
https://en.cppreference.com/w/cpp/string/byte/toupper#Notes

The most important part is:

To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char

It also gives this example:

std::string str_toupper(std::string s) {
    std::transform(s.begin(), s.end(), s.begin(), 
                // static_cast<int(*)(int)>(std::toupper)         // wrong
                // [](int c){ return std::toupper(c); }           // wrong
                // [](char c){ return std::toupper(c); }          // wrong
                   [](unsigned char c){ return std::toupper(c); } // correct
                  );
    return s;
}

Also, you might want to read this:

my environment is gcc version 4.9.2 (tdm-1) in Code::blocks 16:01
Adding #include but the problem is still existed. the log shows

||=== Build: Debug in test (compiler: GNU GCC Compiler) ===|
D:\c++\test\main.cpp||In function 'int main()':|
D:\c++\test\main.cpp|8|error: no matching function for call to 'transform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)'|
D:\c++\test\main.cpp|8|note: candidates are:|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_algo.h|4152|note: template<class _IIter, class _OIter, class _UnaryOperation> _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation)|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_algo.h|4152|note:   template argument deduction/substitution failed:|
D:\c++\test\main.cpp|8|note:   couldn't deduce template parameter '_UnaryOperation'|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_algo.h|4189|note: template<class _IIter1, class _IIter2, class _OIter, class _BinaryOperation> _OIter std::transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation)|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_algo.h|4189|note:   template argument deduction/substitution failed:|
D:\c++\test\main.cpp|8|note:   candidate expects 5 arguments, 4 provided|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

but if I add a function:

char ctoupper(char c){
    return std::toupper(c);
}

and Using std::transform(str.begin(), str.end(), str.begin(), ctoupper); is correct.

And using
static_cast<int(*)(int)>(std::toupper),
[](int c){ return std::toupper(c); }, [](char c){ return std::toupper(c); },
[](unsigned char c){ return std::toupper(c); }
all of them can run correctly.

Im chaos. hahaha

Try this:

// For std::cout, std::cin
#include <iostream>

// For std::string
#include <string>

// For std::transform
#include <algorithm>

// For std::toupper
#include <cctype>

int main()
{
	std::string string("abcdefg");
	std::transform(string.begin(), string.end(), string.begin(), std::toupper<char>);
	std::cout << string << '\n';
	std::cin.get();
}

Or this:

// For std::cout, std::cin
#include <iostream>

// For std::string
#include <string>

// For std::transform
#include <algorithm>

// For std::toupper
#include <cctype>

int main()
{
	std::string string("abcdefg");
	std::transform(string.begin(), string.end(), string.begin(), std::toupper<int>);
	std::cout << string << '\n';
	std::cin.get();
}

If either of those works then I think I know what the problem is.

None can work.
that is the log:

||=== Build: Debug in test (compiler: GNU GCC Compiler) ===|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_algo.h||In instantiation of '_OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation) [with _IIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; _OIter = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >; _UnaryOperation = int (*)(int, const std::locale&)]':|
D:\c++\test\main.cpp|7|required from here|
C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\4.9.2\include\c++\bits\stl_algo.h|4163|error: too few arguments to function|
||=== Build failed: 1 error(s), 2 warning(s) (0 minute(s), 0 second(s)) ===|

I just think maybe that is about ambiguity problem.
I found toupper has two versions.

in header <locale>
template< class charT >
charT toupper( charT ch, const locale& loc );

in header <cctype>
int toupper( int ch );

but I just using only, so weird.

Ah, that explains a lot.

One of the other headers must be including <locale>,
which as you say defines template<typename Char> Char toupper(Char, const std::locale &).

The main reason I decided to ask if std::toupper<char> made a difference is because of the message <unresolved overloaded function type>,
which implies that std::toupper is overloaded.

According to cppreference, if only <cctype> is included then there should only be one std::toupper defined, no other overloads, and thus the code should be unambiguous (which is why the code I first posted compiled for me and not for you).

I wanted to see if there was a template overload declared,
because that would (partly) explain why the compiler is having a problem resolving the overloads.
I wasn’t sure if std::toupper from <locale> was the issue,
or if the standard library implementation was declaring another overload somewhere,
but I suspected testing std::toupper<char> would provide the answer.

I’ve since tried to compile the following:

// For std::cout, std::cin
#include <iostream>

// For std::string
#include <string>

// For std::transform
#include <algorithm>

// For std::toupper
#include <cctype>

// To test for errors
#include <locale>

int main()
{
	std::string str("abcdefg");
	std::transform(str.begin(), str.end(), str.begin(), std::toupper);
	std::cout << str << '\n';
	std::cin.get();
}

And I also get a number of errors (different messages because I’m not using GCC, but the same cause).

This implies that if both int std::toupper(int) and template<typename Char> Char std::toupper(Char, const std::locale &) are defined, the compiler can’t decide which std::toupper to use.

The reason using static_cast<int(*)(int)>(std::toupper) solves this problem is because only int std::toupper(int) can be converted to int(*)(int),
whereas the templated version (template<typename Char> Char std::toupper(Char, const std::locale &)) can’t be converted to int(*)(int),
so that removes the ambiguity.

The same is true of:

  • [](int c){ return std::toupper(c); }
  • [](char c){ return std::toupper(c); }
  • [](unsigned char c){ return std::toupper(c); }
  • char ctoupper(char c) { return std::toupper(c); }

They all remove the ambiguity that’s causing template resolution to fail with std::transform(str.begin(), str.end(), str.begin(), std::toupper);.

The reason ::toupper succeeds is because it’s the same as int std::toupper(int) from <cctype>,
whereas the std::toupper from <locale> doesn’t have an equivalent in the global namespace.

::toupper exists in the global namespace because of the rules governing the <cxxx>-style headers,
which are the C++ versions of the headers from C.

Specifically, <cctype> is the C++ version of <ctype.h>,
and the standard library requires that std::toupper is defined in the std namespace,
while also allowing (but not guaranteeing) that ::toupper to be declared in the global namespace.
(The same is true of all headers and functions ‘borrowed’ from C.)


But the explanation is not over yet.
That explains why the others work, and half of why the compiler gets confused,
but there’s more to it than that.

The error itself happens simply because the way the standard library implementations define std::transform means that the compiler can’t decide which template instantiation is better.
It’s probably not worth trying to figure out exactly why that is,
for reasons I will explain in a moment.

Now, the interesting part is that technically speaking, this error is completely avoidable.
It is entirely possible to define std::transform in such a way that it would correctly deduce that it needs to use the std::toupper from <cctype> and not the one from <locale>.

However, the standard library does not require this, and doing so is somewhat difficult,
so the authors of your compiler and my compiler have chosen not to bother.

Most likely they decided it was too much effort for something so minor.
Or possibly it is because the facilities to do so (<type_traits> and decltype) were only introduced in C++11 and std::transform has been around since C++98.
Or maybe they just aren’t aware of the issue.

Whatever the reason, the only ways to change this are to:

  • Convince the GCC team that they should modify std::transform to deduce the better toupper
  • Convince the C++ standards committee that std::transform should be required to be correctly deduce the better toupper

Both of which are a lot of effort and unlikely to happen.
(And ultimately C++20 is introducing a better solution in the form of concepts and constraints.)

Thanks a lot!!!
Could l simply understand that std::transform cant deduce the better toupper ?

Sort of.

The version of std::transform in GCC’s implementation of the standard library can’t,
but it is possible to write a version of std::transform that can.


Writing one that can would involve using SFINAE (‘Substitution Failure Is Not An Error’) to detect whether std::declval<UnaryOperation>()(*std::declval<InputIterator>()) is a valid expression.

If UnaryOperation is int std::toupper(int) and InputIterator is std::string::iterator then the expression should be valid,
which means int std::toupper(int) would be a valid match,
but if UnaryOperation were template<typename Char> Char std::toupper(Char, const std::locale &) then substitution would fail,
which would mean <locale>'s std::toupper isn’t a valid match,
so the compiler would choose <cctype>'s std::toupper because it was an exact match.


A while back I wrote an explanation of SFINAE to demonstrate some of the ways it’s used and explain roughly how it works: