14

I've seen code like this:

std::string str = "wHatEver";
std::transform(str.begin(), str.end(), str.begin(), ::tolower);

And I have a question: what does mean :: before tolower?

and std::tolower not works, but ::tolower works OK

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
VextoR
  • 5,087
  • 22
  • 74
  • 109
  • 4
    Technically, it's called the **[scope resolution operator](http://en.wikipedia.org/wiki/Scope_resolution_operator)**. That should give you a term to begin your search for more details. – Cody Gray - on strike Mar 11 '11 at 09:00

4 Answers4

12

As to why the :: is necessary: the standard defines two tolower's, a function template in std::, and a simple function in both :: and std::. Depending on which headers have been included (and that includes headers indirectly included from other headers, which you may not know about), either one, the other, or both may be visible. Using :: ensures that the older one, from the C standard, is used. (If the one in std:: is considered, the call will be ambiguous, since transform is a template itself, and the compiler will not be able to deduce the template arguments.)

While I'm at it, I might mention that using ::tolower like this is undefined behavior, at least if plain char is signed. The input to ::tolower is an int, and must be in the range 0...UCHAR_MAX, or EOF. If plain char is signed, some of the characters may have negative encodings, which results in undefined behavior. In practice, most implementations make this work. For all characters except 0xFF (ÿ in Latin 1). If you're not concerned with portability, some compilers have a switch to make char unsigned---use it. Otherwise, write a small functional object to handle it correctly, either:

struct ToLower
{
    char operator()( char ch ) const
    {
        return ::tolower( static_cast<unsigned char>(ch) );
    }
};

or (better, but significantly more work---only worth it if your using it a lot), a functional object whose constructor takes a locale (defaulting to the global locale) and contains a reference to an std::ctype, which it uses for the tolower function. (Of course, if you're really internationalized, tolower probably doesn't have any meaning. And you'll be using UTF-8, which is a multi-byte encoding, and doesn't work with any of the available possibilities.)

PythonJin
  • 4,034
  • 4
  • 32
  • 40
James Kanze
  • 150,581
  • 18
  • 184
  • 329
10

Means that it is explicitly using the tolower in the global namespace (which is presumably the stdc lib one).

Example:

void foo() {
    // This is your global foo
}

namespace bar {
    void foo() {
        // This is bar's foo
    }
}

using namespace bar;

void test() {
    foo();   // Ambiguous - which one is it?
    ::foo(); // This is the global foo()
}
EboMike
  • 76,846
  • 14
  • 164
  • 167
  • thanks, but I can't understand, you wrote - using namespace bar; why compiler will not use foo from bar? why you need to write bar::foo after using namespace bar; Can you please explain? – VextoR Mar 11 '11 at 09:09
  • 1
    "using namespace bar" means that `foo()` by itself implies `bar::foo()`. However, maybe you meant to use the `foo()` in the global scope? That can also be accessed via `foo()`. So `foo()` could be used for both. Now the compiler isn't sure which one you meant, so you have to specify. – EboMike Mar 11 '11 at 09:11
  • @EboMike "`foo()` by itself implies `bar::foo()`" is too strong. Name lookup considers `bar::foo` when looking for a match for `foo` (and in this case finds ambiguity with `::foo`) – Caleth Jul 12 '18 at 14:17
4

Use the version from the global namespace. (Probably included <ctypes.h> and not <cctypes> if std:: doesn't work)

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
  • Thanks. I use Visual C++ 6. So :: says to use tolower from global namespace – VextoR Mar 11 '11 at 08:54
  • Yes, the other potential overload of tolower are in `` (I said potential because I don't know how conformant VC++6 is on that point... why use such an old compiler?) – AProgrammer Mar 11 '11 at 09:00
  • "why use such an old compiler?" Oh, don't ask)) It's because of very old project – VextoR Mar 11 '11 at 09:02
  • 2
    That's the only one valid reason (But I'd plan for a switch if the project has to be continued). We see far too many learners still using it. – AProgrammer Mar 11 '11 at 09:08
0

:: is the global namespace.

#include <iostream>

void bar()
{
    std::cout << "::bar" << std::endl;
}

namespace foo
{
    void bar()
    {
        std::cout << "foo::bar" << std::endl;
    }
}

int main()
{
    bar();
    foo::bar();
    ::bar();
    using namespace foo;
    foo::bar();
    ::bar(); // bar() would be ambiguous now without ::
}
jhasse
  • 2,379
  • 1
  • 30
  • 40
  • the comment wasn't clear enough: bar() without :: would be ambiguous – jhasse Mar 11 '11 at 09:01
  • 5
    @Nawaz: Read the comments carefully before downvoting. He says that `::bar()` would be ambiguous without the `::`. In fact, [it is](http://www.ideone.com/Pmi5u). – Cody Gray - on strike Mar 11 '11 at 09:03
  • @Cody: the comment is edited within 5 mins. Previously it was *"bar() would be ambiguous"* which is obviously wrong! – Nawaz Mar 11 '11 at 09:09
  • Ironically, the original comment was *ambiguous*! (It wasn't wrong, per se. The current interpretation is perfectly logical, even given the original wording.) – Cody Gray - on strike Mar 11 '11 at 09:22
  • @Cody: The code was NOT ambiguous, but the comment was saying *"bar() would be ambiguous"*. Is there any confusion now? – Nawaz Mar 11 '11 at 09:29
  • @Cody: But I didn't get the comment in which you said *"Ironically, ..."*. :D – Nawaz Mar 11 '11 at 09:43
  • @Nawaz: It was just a joke. I meant that jhasse's original comment in the source code was ambiguous. It was unclear *which* version of `bar()` he meant would be ambiguous. The first time I read it, I interpreted it correctly, but I could see how you assumed something else entirely. – Cody Gray - on strike Mar 11 '11 at 09:45