简体   繁体   中英

Scope resolution operator and const

Let's take the following code:

#include <string> // std::string    
using namespace std;
int main() {
  //const::int i = 42;       -> Error: "expected id-expression before 'int'"
  const::string str = "Foo"; // No error: why?
}

Why does this code compiles? The error "expected id-expression before XXX" is only present when XXX is a fundamental type.

const::char c = 1;   // error: expected id-expression before 'char'
const::double d = 2; // error: expected id-expression before 'double'
const::float f = 3;  // error: expected id-expression before 'float'
const::bool b = 4;   // error: expected id-expression before 'bool'

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.

::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";
}

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.

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 , optionally preceded by a nested-name-specifier ,
  • A nested-name-specifier template simple-template-id ,
  • One of the built-in primitive types,
  • The auto keyword, or
  • A decltype-specifier .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM