Why does c++'s namespace scope also include file scope(in c)? - c++

C(ISO/IEC 9899:2011) has no concept of namespace, when referring global variable's scope, the standard use file scope:
Every other identifier has scope determined by the placement of its declaration (in a declarator or type specifier). If the declarator or type specifier that declares the identifier appears outside of any block or list of parameters, the identifier has file scope, which terminates at the end of the translation unit. If the declarator or type specifier that declares the identifier appears inside a block or within the list of parameter declarations in a function definition, the identifier has block scope, which terminates at the end of the associated block. If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator. If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
However, in c++(at least ISO/IEC 14882:2011), file scope is never used and use namespace scope instead:
The declarative region of a namespace-definition is its namespace-body. Entities declared in a namespace-body are said to be members of the namespace, and names introduced by these declarations into the declarative region of the namespace are said to be member names of the namespace. A namespace member name has namespace scope. Its potential scope includes its namespace from the name's point of declaration onwards; and for each using-directive ([namespace.udir]) that nominates the member's namespace, the member's potential scope includes that portion of the potential scope of the using-directive that follows the member's point of declaration.
As we know, c++ is inspired a lot from C, so many definitions of terms also derive from c, though they are virtually two different languages now. IMO, there should be a reason that c++ use namespace scope instead of file scope, but I don't know. What's behind it?

The C++ standard doesn't mention file scope because it isn't trying to explain things in C terms. It defines and uses its own terms. In this case, it is under the definition of namespaces:
[basic.namespace]
2 The outermost declarative region of a translation unit is a
namespace; see [basic.scope.namespace].
This declarative region, in C++ terms, is the equivalent of C's file scope. The C++ standard uses these definitions because it intends to support namespace declarations, that allow us to partition this scope into smaller pieces.
C has no such feature, so it speaks only of things at file scope as the its outermost scope, because said definition is enough.

You're asking about file scope, not function scope.
The reason that C++ instead talks about namespace scope, is that it has namespaces. C doesn't. So of course C wouldn't have namespace scope.
C and C++ are different languages. C++ doesn't change things to "not be C", it changes things because its designers consider the changes to make the language inherently "better", either directly, or by consequence of the existence of some C++-only feature that in turn makes the language "better" than C.

Related

what are lookup rules when a name occured before function's declarator-id?

#include <iostream>
typedef int Name;
Name func(int){
return 0;
}
int main(){
}
Consider the above code, I can't find a bullet in [basic.lookup.unqual] that can interpret how to lookup Name for definition of func. I will cite some potential rules here:
A name used in global scope, outside of any function, class or user-declared namespace, shall be declared before its use in global scope.
A name used in a user-declared namespace outside of the definition of any function or class shall be declared before its use in that namespace or before its use in a namespace enclosing its namespace.
In the definition of a function that is a member of namespace N, a name used after the function's declarator-id shall be declared before its use in the block in which it is used or in one of its enclosing blocks ([stmt.block]) or shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N's enclosing namespaces
Please note the emphasized parts, it seems that my case does not satisfy these bullets, because Function definitions have the form
function-definition:
attribute-specifier-seq(opt) decl-specifier-seq(opt) declarator virt-specifier-seq(opt) function-body
Let me analyze the first bullet. It says outside of any function,but according to the Function definitions rule, I think that Name is within the function(definition), bullet 1 isn't satisfied. Bullet 2 is similar with that of bullet 1. Bullet 3 says that the name used after the function's declarator-id, in my case, the Name is used before the function's declarator-id. So what's the rule about this case to find the unqualified name Name?
My confusions:
In my example ,the Name,func ,(int) and { return 0;}(function body) are all parts of that function definition,So:
what is outside of any function,such as the func in my example,where's area of outside of that function?
what is outside of the definition of any function,such as the func definition in my example,where's area of outside of the definition of that function?
I think that Name is within the function(definition), bullet 1 isn't satisfied.
Bullet 1 didn't say "function(definition)". It said "outside of any function". It doesn't specify declaration or definition; merely "outside of any function".
Since being inside or outside of a "function" is not a defined concept, it must be read as plain English. Is a function prototype "outside of the function"? Visually speaking, there's nothing special about a function prototype that is suggestive of an inside/outside distinction. By contrast, the function body's block scope does suggest an inside/outside distinction.
The intent of the text of course is quite obvious; it's talking about the function body. The rule equates "function", "class" and "namespace", all of which have a block that defines scoping for names. That is the most logical place for any inside/outside distinction, so it seems pretty obvious that it's saying that the global scope consists of everything that isn't in the scope of a function body, the scope of a class definition, or the scope of a namespace body.
So this can be easily handled with an editorial change.
Note that the committee recognizes the wording of this section (among others in that area) as somewhat defective, and there's a proposal for rewriting it into something more coherent in C++23. The new wording from the proposal completely rewrites this section.

C++ out-of-namespace definition

On this site there is the following paragraph:
Out-of-namespace definitions and redeclarations are only allowed after the point of declaration, only at namespace scope, and only in namespaces that enclose the original namespace (including the global namespace) [and they must use qualified-id syntax (since C++14)]
I used [] to delimit the section that the (since C++14) construct refers to.
My question is how were out-of-namespace definitions made before C++14, if they did not have to use qualified-id syntax?
I looked at a C++11 standard draft and I found the following:
Members of a named namespace can also be defined outside that namespace by explicit qualification (3.4.3.2)
of the name being defined, provided that the entity being defined was already declared in the namespace
and the definition appears after the point of declaration in a namespace that encloses the declaration’s
namespace. [...]
Is there a difference between qualified-id syntax and explicit qualification?
Thank you.

Template alias scope

As per http://en.cppreference.com/w/cpp/language/type_alias, aliases are block-level declarations. It doesn't say anything special about template aliases, so it should be read that template aliases are block-level declarations as well.
However, it is impossible to use template aliases at block level. The errors are different depending on the compiler - while g++ gives a meaningful message, saying that templates are not allowed at block scope, clang is completely cryptic. (example: http://coliru.stacked-crooked.com/a/0f0862dad6f3da61).
Questions I have so far:
Does cppreference fail to specify that template aliases can not be used at block scope? (Or do I need to take a reading course?)
Are the compilers correct in denying template aliases on block level (the feature I find very interesting for my particular coding habits)
If the answer to the second is Yes, what might be the rationale for this? Why would compiler deny me this pure syntax sugar?
An alias template is [temp.alias]
A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to
be a alias template. An alias template is a name for a family of types. The name of the alias template is a
template-name.
And if we look at 14.2 [temp] we have
A template-declaration can appear only as a namespace scope or class scope declaration. In a function
template declaration, the last component of the declarator-id shall not be a template-id.
So yes cppreference is off saying that it can be declared at block scope and your compilers are correct. If you do click on the link of block declarations It will bring you to a list of declarations and in that it has Template declaration and in there it has
declaration of a class (including struct and union), a member class or member enumeration type, a function or member function, a static data member at namespace scope, a variable or static data member at class scope, (since C++14) or an alias template (since C++11) It may also define a template specialization.
As for why the standard says that templates can only be declared in namespace scope or class scope I like James Kanze answer
The problem is probably linked to the historical way templates were implemented: early implementation techniques (and some still used today) require all symbols in a template to have external linkage. (Instantiation is done by generating the equivalent code in a separate file.) And names defined inside a function never have linkage, and cannot be referred to outside of the scope in which they were defined.
The compilers are behaving correctly.
Section 14 of the C++14 standard:
A template-declaration can appear only as a namespace scope or class
scope declaration.

How is the following passage from the standard to be interpreted?

§3.3.6/1 (C++11)
The declarative region of a namespace-definition is its namespace-body. The potential scope denoted by
an original-namespace-name is the concatenation of the declarative regions established by each of the
namespace-definitions in the same declarative region with that original-namespace-name....
The definition of a declarative region is as follows (§3.3.1/1):
Every name is introduced in some portion of program text called a declarative region, which is the largest part
of the program in which that name is valid, that is, in which that name may be used as an unqualified name
to refer to the same entity. ...
The two taken together would seem to imply that the name of a namespace can only be used (unqualified) inside the namespace body itself. But, clearly, this is false. So what does it mean for the declarative region of a namespace definition to be the body, when the name of the namespace can in fact be used (unqualified) outside the namespace body?
Also, I just don't understand this at all (re-quoted from above):
The potential scope denoted by
an original-namespace-name is the concatenation of the declarative regions established by each of the
namespace-definitions in the same declarative region with that original-namespace-name.
The standard is not talking about what you think...
I think your confusion lies with the fact that you are mistakingly assuming that the text is about the namespace name itself, when the standard is really talking about names introduced inside the namespace in question.
What about the quoted thing that "just doesn't make sense"?
The potential scope denoted by an original-namespace-name is the concatenation of the declarative regions established by each of the namespace-definitions in the same declarative region with that original-namespace-name.
The above might be easiest to describe with an example:
.--- namespace definition
| .--- original-namespace-name
v v
namespace N { <-------------------------------.
int x = 0; <---+--- declarative region (1)
} <-------------------------------------------'
.--- another namespace definition of `N`
| .--- original-namespace-name
v v
namespace N { <-------------------------------.
int y = x; <---+--- declarative region (2)
} <-------------------------------------------'
Note: The potential scope of int x is both (1) and (2), ie. "concatenation of the declarative regions" introduced.
In the example we have two namespace-definitions for the original-namespace-name N, we also have two declarative regions, but the "potential scope" inside the namespace named N is both (1), and (2).
As long as the namespace definitions themselves are in the same declarative region, and share the same original-namespace-name, they refer to the same namespace.
Introducing another such namespace definition will just add more room to the potential scope (by appending another declarative region) of the variables previously declared inside it.
potential scope, and declarative region; what are they?
a declarative region is the part of a program where a name can be referred to without being qualified.
The potential scope is the scope in which a name is potentially valid, it's the entire scope in which the name could refer to the same entity.
3.3.1p1 Declarative regions and scope [basic.scope.declarative]
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which the name may be used as an unqualified name to refer to the same entity.
In general, each particular name is valid only within some possible discontiguous portion of program text called its scope. To determine the scope of a declaration, it is sometimes conventient to refer to the potential scope of a declaration.
The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name. In that case the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.

Use of extern in block scope

clang, gcc and VS2013 all complain about redefinition of w in main(), but I couldn't find in the Standard anything disallowing this.
namespace N {
extern int j;
int j;
}
int main()
{
extern int w;
int w;
}
These paragraphs say something about the use of an extern declaration in block scope, but they don't seem to justify the error message:
§3.3.1/4
Given a set of declarations in a single declarative region, ...
[ Note: These restrictions apply to the declarative region into which
a name is introduced, which is not necessarily the same as the region
in which the declaration occurs. In particular,
elaborated-type-specifiers (7.1.6.3) and friend declarations (11.3)
may introduce a (possibly not visible) name into an enclosing
namespace; these restrictions apply to that region. Local extern
declarations (3.5) may introduce a name into the declarative region
where the declaration appears and also introduce a (possibly not
visible) name into an enclosing namespace; these restrictions apply to
both regions. —end note ]
§3.3.2/10
[ Note: Friend declarations refer to functions or classes that are
members of the nearest enclosing namespace, but they do not introduce
new names into that namespace (7.3.1.2). Function declarations at
block scope and variable declarations with the extern specifier at
block scope refer to declarations that are members of an enclosing
namespace, but they do not introduce new names into that scope. —end
note ]
I believe this is mostly covered by §3.5/6.
In particular:
The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration. If there is more than one such matching entity, the program is ill-formed. Otherwise, if no matching entity is found, the block scope entity
receives external linkage.
So, the extern int w; declares a w that has linkage (external linkage, in this case, since no matching entity is visible at that point).
Then you attempt to define a local w which has no linkage (by §3.5/8).
That gives two declarations of the same name at the same scope, but with different linkages. That's prohibited by §3.3.1/4:
Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,
they shall all refer to the same entity, or all refer to functions and function templates; or
exactly one declaration shall declare a class name or enumeration name that is not a typedef name
and the other declarations shall all refer to the same variable or enumerator, or all refer to functions and function templates; in this case the class name or enumeration name is hidden (3.3.10).
Neither refers to a function, function template, class name, or enumeration name, so none of these "escape clauses" applies. The two declarations must refer to the same entity, which must have both external linkage and no linkage. Since that's impossible, the code is ill-formed.
Here is my interpretation: In §3.3.1/3 the standard says:
The names declared by a declaration are introduced into the scope in which the declaration occurs, except that the presence of a friend specifier (11.3), certain uses of the elaborated-type-specifier (7.1.6.3), and using-directives (7.3.4) alter this general behavior.
As extern declarations are not listed as exception, the name is introduced in the block scope, which is why you get the error when you try to redeclare it.
The paragraph you quoted says
but they do not introduce new names into that scope.
which is a bit ambiguous, as both block scope and namespace scope are mentioned. The standard would contradict itself if it referred to block scope, so I assume that namespace scope is meant.