Re: Linkage of namespace scope reference
"Alf P. Steinbach" wrote:
* johnchx2@yahoo.com:
Alf P. Steinbach wrote:
Formally that's backwards, because for a reference it's the initializer
that determines whether the declaration is a definition, not the other
way around.
It has nothing to do with whether the name being declared is a
reference, it has to do with whether the name being declared is
explicitly declared extern.
Any declaration with the extern keyword is also a definition if and
only if an explicit initializer is present.
How is that different from what I wrote?
I disagree with the phrase "for a reference" in your formulation. For
a declaration without an explicit initializer to be a non-definition,
it is neither necessary nor sufficient for the name to be declared with
reference type. What is necessary (and sufficient) is for "extern" to
appear in the declaration. The rules for reference and non-reference
declarations seem consistent in this regard.
Perhaps I misunderstood you, but I thought you were suggesting that
references were a special case.
Declarations without the
extern keyword are always definitions. (I'm assuming we're just
talking about variable declarations; static data members, functions and
types follow...sigh...different rules.)
Well, a reference isn't a variable, so that's not what we're talking about.
True; I was groping around for a shorthand expression and came up with
a bad one.
It would be better to say: a declaration is a definition unless 3.1/2
says it's not. One of the things 3.1/2 says isn't a definition is a
declaration that includes the extern specifier and doesn't include an
initializer.
The 'const' for something that a reference refers to is not a 'const'
for the reference itself.
The analogous case for non-reference would be a const pointer's linkage
being determined by the constness of what the pointer points to.
I think that is a mis-perception
What is a mis-perception, do you think?
Perhaps "mis-perception" isn't the best phrase. Say rather, it's a
poor analogy.
that comes from thinking of references
as automatically dereferenced pointers, rather than as what the
standard says they are: pure aliases. Consider:
const int a = 0;
const int& b = a;
"a" names a const object. "b" also names a const object (as it
happens, the same one). They're alike. It's non-sensical to think of
"b" as naming "the reference", because no such object exists to name.
In order to declare 'b' as an 'extern' reference you need to be aware
that it's a reference, and declare it in other translation units as a
reference.
Sure, but that's beside the point that I'm trying to make. Let me try
to make it better. Once you accept that const-ness can affect the
default linkage of a name (and *that's* the part that *I* find
surprising and arbitrary), it shouldn't be surprising that it's the
const-ness of the lvalue expression formed by the use of the name that
matters.
So:
const int a = 0;
const int* pa = &a; // lvalue "a" has const type
const int& b = a;
const int* pb = & b; // lvalue "b" has const type
const int** ppb = & pb; // lvalue "pb" had non-const type
"a" and "b" have internal linkage because the corresponding lvalues
have const type. "pa" and "pb" have external linkage because the
corresponding lvalues have non-const type. The types of "*pa" and
"*pb" don't enter into it.
There's a verbal analogy created by the phrases "pointer-to-const" and
"reference-to-const." But this is purely word-play, and it is
misleading. A name declared with type const T* denotes an object of
non-const pointer type. A name declared with type const T& denotes an
object of type const T. It does not denote "a reference".
I think the only sensible way to think of 'b' is as a reference.
For the purpose of 'extern', which is what this tread is all about, it
won't do to treat 'b' as simply an alternate name for an object.
'extern const int b;' in some other translation unit does not refer to
'extern const int& b = a' in this one.
The question isn't really whether we can ignore the fact that b has
reference type, but whether it is analagous to a pointer to the
referenced type. I don't think that analogy is a good one, for the
very reason you give: it leads to the wrong conclusion about the
linkage of the name. (It also gives a false impression of what the
name denotes.)
(Of course, in some situations, the implementation will use a pointer
"under the hood," e.g. for reference members. But that's an
implementation detail, irrelevant to the *concept* of references.)
Details matter, understanding the implementation matters, and yes,
concepts matter: none of it is irrelevant.
Sure. But what I'm driving at is that by chosing which aspects to
emphasize, it is possible to come up with exposition that is either
more or less confusing. I don't think that there's any doubt that it
is possible to arrive at an exposition of these rules that is both
confusing and correct. (Arguably, the standard itself if sufficient
evidence of that.) The interesting question is whether there is also
an exposition which is both correct and "non-confusing."
I think that, at least for non-members, there is. Something like:
(a) All declarations are definitions, except when explicitly declared
extern. An extern declaration is a definition if and only if it
includes an explicit initializer.
(b) Some definitions require an explicit initializer, specifically:
definitions of variables of const type (for types without a
user-defined default constructor) and definitions of names with
reference type.
(c) Names declared with const type (that is, names whose evaluation as
an lvalue will have const type) have internal linkage by default.
Names declared with non-const type have external linkage by default.
Names can be given non-default linkage by means of keywords static and
extern or by means of a linkage specifier.
These may not cover every single case (I'm leaving members out, for
example), but nothing -- with the possible exception of (b), which I
suspect is inherited from C -- jumps out at me as wildly arbitrary. Do
you disagree?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]