Many thanks for your answers.
There're still a few issues that
bother me. Although, as you've said, static under namespace is
deprecated, I feel not so comfortable if I don't completely understand
it.
If I have
then "a" has external linkage, but if I have
namespace N{
static A a;
}
then "a" has internal linkage, is this right?
Correct.
I think "internal linkage" means it's only accessible within
this current translation unit, is this also right?
Not really. Although it's common to think of it in such terms,
linkage is really concerned with whether two (fully qualified)
names refer to the same object (or function, or class, or
whatever). In the above, the fully qualified name is N::a, and
the name is "accessible" in any translation unit which declares
it. In the first case, it has external linkage, which means
that all of the names N::a refer to the same, unique object,
regardless of which translation unit they are in. In the
second, with the static, the name as internal linkage: all of
the declarations within a single translation unit refer to the
same, unique object, but each translation unit has a different
object.
Furthermore, I tried one example as follows:
//test.h
class A{
public:
int x;
A():x(10){}
};
namespace foo{
static extern A b;
Did this compile? It shouldn't: both static and extern are
"storage class specifiers", and "At most one
storage-class-specifier shall appear in a given
decl-specifier-seq."
//test.cpp
#include "test.h"
//testT.cpp
#include<iostream>
#include "test.h"
int main(){
cout << foo::b.x << endl;
return 0;
}
However, the compiler error was
"multiple storage classes in declaration of 'b'"
Exactly what it says. The keywords "auto", "register",
"static", "extern" and "mutable" are storage class specifiers,
and the standard says that at most one can appear in any given
declaration.
Formally, this is a purely syntactic restriction, but the
motivation is that in general, the semantics of each of these
keywords conflict. (One could argue about auto and register, I
suppose.) In this particular case, "static" says that the
variable has internal linkage, and "extern" says that it has
external linkage. Extern also says that it is only a
declaration, and not a definition. The C++ declaration syntax
just grew, and isn't always as coherent or as logical as one
might like. Thus:
namespace A {
int a1 ; // external linkage, definition.
extern int a2 ; // external linkage, declaration.
static int a3 ; // internal linkage, definition.
int const a4 ; // *internal linkage, definition.
extern int const a5 ; // external linkage, declaration.
static int const a6 ; // *internal linkage, definition.
int i1 = 42 ; // external linkage, definition.
extern int i2 = 42 ; // external linkage, definition!
static int i3 = 42 ; // internal linkage, definition.
int const i4 = 42 ; // internal linkage, definition.
extern int const i5 = 42 ; // external linkage, definition.
static int const i6 = 42 ; // internal linkage, definition.
}
The declarations marked * are in fact illegal, as a definition
of a const object is illegal unless the object either has a
non-trivial constructor or an initializer. Note that the table
is full of incoherences and oddities---note in particular the
role of const (which logically is completely orthogonal), and
the fact that an initialization forces the declaration to be a
definition, even if it is extern. (And that to define a const
object with external linkage, you have to use extern.)
Also, these declarations suppose that the object has not been
previously declared. Something like:
namespace A {
static int const x = 42 ;
extern int const x ;
}
is perfectly legal---linkage is established by the first
declaration, and cannot be changed later, and extern only means
external linkage if there has been no previous declaration. On
the other hand, inversing them is not---static means internal
linkage, always, so the linkages conflict.
The only local scope that I've seen is within a function body, is
there any other kind of local scope?
Local scope is always within a function body, or more exactly, a
compound statement (but a compound statement can only
occur within a function body).
How can a function be declared within such local scope?
void
f()
{
std::vector< int > v( std::istream_iterator< int >( file ),
std::istream_iterator< int >() ) ;
}
. The problem is more often, how can we ensure that a
definition is not a function declaration in local scope; in the
above, the programmer probably wanted to define a local variable
v, using the two iterator constructor of vector. In fact, he has
declared a function (with external linkage, in global scope)
taking two arguments, and istream_iterator<int>, and a pointer
to a function returning and istream_iterator<int>, and returning
a vector<int>.
On the other hand, the intent of:
void
f()
{
extern double g( double ) ;
// ...
}
seems quite clear, although it's not the sort of thing one would
encourage.
By the way, I think "no linkage" means it is only accessible
within that local scope where it's defined, is this correct?
No linkage means that no other declaration can refer to the
object in question. For example:
void
f()
{
int a ; // No linkage...
{
int a ; // So this can't be the same variable.
// ...
}
}
There's an interesting (perverse?) example of this in the
standard:
static int i ; // 1.
void g()
{
int i ; // 2. Hides the static 1.
{
extern int i ; // 3.
}
}
The line labeled 3 refers to yet a third object (not defined
here): since the declaration at 2 hides the declaration at 1,
the compiler doesn't "see" it, and since the declaration at 2
has no linkage, the declaration at 3 declares a new object, with
external linkage (different from the object with internal
linkage defined at 1).
(And if you aren't thoroughly confused yet, you should be.)
My interpretation about "global" namespace is that I don't use any
"namespace" to surround my object/function, please correct me if I'm
wrong.
Correct. The concept is that the entire translation unit is
encapsulated in an outer namespace, which is called the global
namespace.
Then, why did you say a global object is "an object in
namespace scope and with external linkage"? In other words, do I still
need to use "namespace" to wrap it up?
No. Namespace scope includes objects defined in this imaginary
namespace which encapsulates the entire translation unit. (On
the other hand, it doesn't include built in types, like int.
Which occasionally causes problems when code is counting on
ADL.)
I got the terms "global objects" and "objects at file scope" from the
book Effective C++.
They're frequently used terms. File scope is the term in the C
standard, and was the term in pre-namespace specifications of
C++. Global objects is a pretty good, succinct term for
something which we all understand, even if it has no formal
backing in the standard. (Note too that the original version of
Effective C++ pre-dates namespaces, and that it's entirely
possible that Scott didn't fully update his terminology in later
versions.)
My understanding about them is that a global
object has external linkage (accessible from other translation units),
and a file-scope-object is only accessible within that translation
unit (but not limited to any local scope within that translation
unit). Is this not the intended meaning of the author?
Not at all. First, of course, scope is more or less orthogonal
to linkage: you can declare objects with external linkage in
block scope, and only have the name visible (in that translation
unit) in block scope. Other than that, file-scope is just the
traditional name for global namespace scope, or global scope.
When used in the context of C++, all three mean exactly the same
thing. (Scope and linkage aren't 100% orthogonal, since an
object declared at namespace scope will always have linkage.)
I tried another example, which also failed to compile.
//test.h
namespace foo{
static extern const int x;
Again, two storage class specifiers aren't allowed.
//test.cpp
#include "test.h"
namespace foo{
static const int x = 10;
}
#include "test.h"
#include<iostream>
using namespace std;
int main(){
cout << foo::x << endl;
return 0;
}
However, after I removed the static keyword, it compiled and
worked.
Because the first declaration established the linkage (as
external). See above. And don't expect consistency
.
Does a const inside a namespace have external or internal linkage?
Yes
.
A const at namespace scope has internal linkage by default. It
will have external linkage if either 1) it is declared with the
storage class specifier extern, or 2) there is a previous
declaration of the same object which has external linkage.
Moreover, it just seems to me that I can never declare "static" within
a namespace.
Sure you can:
namespace A {
static int x = 32 ;
}
Do this in several different translation units, and you'll find
that the modifications to x in one are not visible in the other.
Because the x in each translation unit is a different object.
Moreover, do all objects that have external linkage have static
lifetime? not a single exception?
Class members have external linkage, and don't (necessarily) have
static lifetime. What is true is that all objects at namespace
scope have static lifetime, and that all objects declared static
(regardless of their linkage or scope) have static lifetime.
Finally, I noticed that sometimes when I declare a static object, I
need "static" keyword, but when I define it, I don't need "static".
Does this depend on the context or, do we not need "static" in general
when we define it?
No. If their is a previous declaration visible (which has
linkage), the linkage is that of the previous declaration.
(Most of the time, the only declaration of a static variable is
also its definition.)