Let\'s take the following code:
#include // std::string
using namespace std;
int main() {
//const::int i = 42; -> Error: \"expected
::something
tells the compiler to look for something
in global namespace, but int
is keyword (not defined anywhere), while string
(resp. std::string
) is class defined in <string>
so your code is equivalent to this one
#include <string> // std::string
using namespace std;
int main() {
//const ::int i = 42; -> Error: "expected id-expression before 'int'"
const ::string str = "Foo";
}
Your using namespace std;
is bit of a red herring. Note that const::std::string str = "Foo";
also compiles. The reason this compiles (and the reason your const::string str = "Foo";
compiles) is because ::
is the scope resolution operator. Spacing is irrelevant. Just as there's no difference between a+b+c
and a + b + c
, there's no difference between const::string str
and const :: string str
(and similarly, between const::std::string str
and const :: std :: string str
).
::
,::std::
, and std::
are all examples of a nested-name-specifier, which is described in 5.1.1 ¶8 of c++ n3290 (a draft of the C++11 standard). The const
is a keyword and this cannot be interpreted as the leading part of a nested-name-specifier. This means that const::string
can only be interpreted as if you had written const ::string
.
In the context of using namespace std;
at global namespace level, there's nothing wrong with using ::string
because the leading ::
means to look up what follows in the global namespace. You've pulled all of namespace std
into the global namespace. Thus const::string str
declares str
as a const
-qualified variable of type std::string
.
What about const::int i = 42;
? There's no place in the standard for such a construct. Looking at 7.1.6.2 ¶1 (c++n3290), A simple-type-specifier is
A type-name is a class-name, an enum-name, a typedef-name, or a simple-template-id. The built-in primitive types do not fall in the category of a type-name. This means that the following will (and does) compile:
#include <string>
#include <iostream>
typedef int Int; // Now we can use ::Int because Int is a type-name.
using namespace std;
int main() {
const::Int i = 42; // No error.
const::string str = "Foo"; // No error.
cout << i << ' ' << str << '\n';
}
const::string
is parsed as const ::string
. ::string
means to look up string
in the global namespace, and since you have injected std
into the global namespace, std::string
is found and everything is dandy.
int
is a built-in type and isn't in any namespace, so there's no such thing as ::int
or std::int
, hence the error.
It compiles because
using namespace std;
pulls the entire std
namespace into the global namespace, so ::string
is the same as std::string
. Your line in question is actually interpreted as
const ::string str = "Foo";
However, int
is a keyword (and a fundamental type), and not a user-defined name that resides in any namespace. So ::int
doesn't make sense.