Why can’t “transform(s.begin(),s.end(),s.begin(),tolower)” be complied successfully?

Let’s look at a list of options starting with the worst and moving to the best. We’ll list them here and discuss them below:

  1. transform(cbegin(s), cend(s), begin(s), ::tolower)
  2. transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
  3. transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })

The code in your question, transform(s.begin(), s.end(), s.begin(), tolower) will produce an error like:

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

The reason that you were getting an “unresolved overloaded function type” is there are 2 tolowers in the std namespace:

  1. The locale library defines template <typename T> T tolower(T, const locale&)
  2. The cctype library defines int tolower(int)

1 is the solution offered by davka. It addresses your error by leveraging the fact that locale‘s tolower is not defined in the global namespace.

Depending upon your situation locale‘s tolower may merit consideration. You can find a comparison of the tolowers here: Which tolower in C++?


Unfortunately 1 depends upon cctype‘s tolower being defined in the global namespace. Let’s look at why that may not be the case:

You are rightly using #include <cctype>, as doing #include <ctype.h> has been deprecated in C++: http://en.cppreference.com/w/cpp/header

But the C++ standard states in D.3[depr.c.headers]2 of the declarations in the headers:

It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3)

So the only way that we can guarantee our code is implementation independent is to use a tolower from namespace std. 2 is the solution offered by David Rodríguez – dribeas. It leverages the fact that static_cast can:

Be used to disambiguate function overloads by performing a function-to-pointer conversion to specific type

Before we move on, let me comment that if you find int (*)(int) to be a bit confusing you can read more on function pointer syntax here.


Sadly there is one other issue with tolower‘s input argument, if it:

Is not representable as unsigned char and does not equal EOF, the behavior is undefined

You are using a string which uses elements of type: char. The standard states of char specifically 7.1.6.2[dcl.type.simple]3:

It is implementation-defined whether objects of char type are represented as signed or unsigned quantities. The signed specifier forces char objects to be signed

So if the implementation defined a char to mean a signed char then both 1 and 2 would result in Undefined Behavior for all characters corresponding to negative numbers. (If an ASCII character encoding is being used the characters corresponding to negative numbers are Extended ASCII.)

The Undefined Behavior can be avoided by converting the input to an unsigned char before passing it to tolower. 3 accomplishes that using a lambda that accepts an unsigned char by value, then passes it to tolower implicitly converting to int.

To guarantee Defined Behavior on all compliant implementations, independent of character encoding, you’ll need to use transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); }) or something similar.

Leave a Comment