:: operator necessary to use with tolower()?

647 views Asked by At
transform(mystr.begin(), mystr.end(), mystr.begin(), tolower);

I am using the transform function to make a string all lowercase letters, but even after writing "using namespace std;" at the top of my program I get a whole bunch of errors(when writen like above). When I include the :: operator before the tolower parameter (such as below) I don't. Why is this? I thought the tolower function was in the std namespace and It would work like I have above.

transform(mystr.begin(), mystr.end(), mystr.begin(), ::tolower);

I have the following includes:

#include <iostream>
#include <fstream
#include <sstream>
#include <algorithm>
#include <vector>

In the error message I see:

error: no matching function for call to 'transform(std::basic_string<char>::iterator, ...

then it the place where 'tolower' is in the parameter list

, <unresolved overloaded function type>);'
4

There are 4 answers

0
Ed Heal On

The :: is to say it is in the global namespace. It just makes it clear

0
anshabhi On

What is the header file that you have included? Make sure, you include <cctype> and not <ctype.h> .. In the <cctype> all functions have been defined in namespace std.

2
Acha Bill On

It's to resolve the conflict between the overloads of tolower between <cctype>'s int tolower(int c) and <locale>'s template <typename charT> charT tolower(charT c, locale const& loc)

::tolower use that of global scope

0
M.M On

Well , this is a bit complicated. Adding #include <cctype> would probably appear to fix your problem. However there is a bit more going on.

There are these two versions of tolower:

int std::tolower(int ch);                           // #include <cctype>

template<typename charT>
charT std::tolower(charT ch, const std::locale& loc);    // #include <locale>

but there also may be this version:

int ::tolower(int ch);    // #include <cctype> or #include <ctype.h>

because implementations are allowed to inject names from std into the global namespace. Also, you can't count on cctype or locale being included or not, because any standard include may also include any other standard include.


It looks like you are intending to use the version from <cctype>. However, that would be a bug . If you check the documentation for that version of tolower you will see that the argument should be converted to unsigned char before being passed to the function.

IOW, passing a char with negative value to the cctype version of tolower causes undefined behaviour. (Although common implementations support it because it's such a common mistake).

To correct your code and still use the cctype version, you could write:

#include <cctype>

// ...

transform(mystr.begin(), mystr.end(), mystr.begin(), 
    [](char ch) { return std::tolower( (unsigned char)ch ); } );

although it seems a bit simpler to use:

for (char &ch : mystr)
    ch = std::tolower( (unsigned char)ch );

The <locale> version would look like (remembering that it is a function template):

#include <locale>
#include <functional>

// ...

transform(mystr.begin(), mystr.end(), mystr.begin(), 
    std::bind( std::tolower<char>, std::placeholders::_1, std::locale() ) );

or

std::locale loc;

for ( char &ch : mystr )
    ch = std::tolower(ch, loc);