user3678566
user3678566

Reputation:

:: operator necessary to use with tolower()?

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

Upvotes: 4

Views: 685

Answers (4)

M.M
M.M

Reputation: 141628

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

Upvotes: 5

Acha Bill
Acha Bill

Reputation: 1255

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

Upvotes: 4

anshabhi
anshabhi

Reputation: 423

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.

Upvotes: 3

Ed Heal
Ed Heal

Reputation: 60017

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

Upvotes: 2

Related Questions