Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ISO/IEC 14882 §3.3 friend, extern and scope

1 view
Skip to first unread message

Steven T. Hatton

unread,
Dec 8, 2006, 1:22:11 PM12/8/06
to
This note appears in the discussion of name hiding and uniqueness:

§3.3 #4[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
(3.3.1) and friend declarations (11.4) 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.]

This note is item #6 in the discussion of "Point of declaration"
§3.3.1 #6[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 object 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. ]

What exactly do these statements mean?

"[E]laborated-type-specifiers and friend declarations may introduce a
(possibly not visible) name into an enclosing namespace;"

"Local extern declarations may introduce a name into the declarative region
where the declaration appears and also introduce a (possibly not visible)
name into an enclosing namespace;"

"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"

"[O]bject 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."

Not only do I not understand their basic meaning, they seem contradictory to
me. The part about "elaborated-type-specifiers" I take to mean "forward
declarations", and the statement appears to mean that bar is introduced
into the namespace foo in this example:

namespace foo{ class bar; }

But what is it saying the friend declaration is introducing into the
namespace foo in this example?

namespace foo{ struct bar{ friend void baz(int i); }; }

The same goes for extern?

--
Regards,
Steven

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Richard Corden

unread,
Dec 9, 2006, 10:12:47 PM12/9/06
to
Steven T. Hatton wrote:
> This note appears in the discussion of name hiding and uniqueness:
>
> §3.3 #4[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
> (3.3.1) and friend declarations (11.4) 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.]
>
> This note is item #6 in the discussion of "Point of declaration"
> §3.3.1 #6[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 object 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. ]
>
> What exactly do these statements mean?
>

Here are some examples:

void b1 ()
{
void f1 ();
}

void b2 ()
{
f1 (); // 'f1' not visible
}

int f1 (); // error: conflicts with 'void f1 ()'


And for friends:

class A
{
public:
friend void f2 ();
};

void b3 ()
{
f2 (); // 'f2' not visible
}

int f2 (); // error: conflicts with 'void f2 ()'

Hope this explains it.

Regards,

Richard


--
Richard Corden

Steven T. Hatton

unread,
Dec 10, 2006, 3:26:12 PM12/10/06
to
Richard Corden wrote:

> Steven T. Hatton wrote:
>> This note appears in the discussion of name hiding and uniqueness:
>>
>> §3.3 #4[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 (3.3.1) and friend declarations (11.4) 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.]
>>
>> This note is item #6 in the discussion of "Point of declaration"
>> §3.3.1 #6[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 object 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. ]
>>
>> What exactly do these statements mean?
>>
>
> Here are some examples:
>
> void b1 ()
> {
> void f1 ();
> }

I guess that's legal. I had never even considered it. I assume that makes
it possible to call f1(); within the scope of b1(); without having a prior
definition of f1().

> void b2 ()
> {
> f1 (); // 'f1' not visible
> }
>
> int f1 (); // error: conflicts with 'void f1 ()'

How so? I'll grant that my compiler might be wrong, but it certainly
accepts the following:

//bla.cpp
#include <iostream>

void b1 () { void f1 (); }

int f1() { return 123; }

int main(){
b1();
f1();
}

c++ -o bla bal.cpp
Compilation finished at Sun Dec 10 10:41:09
c++ --version
g++ (GCC) 4.0.2 20050901 (prerelease) (SUSE Linux)


I can come up with a situation in which those declarations are both
meaningful and used without conflict. For example, I could define

namespace bla {
void f1() { std::cout << "void bla::f1()"; }
}

void b1 () {
void f1 ();

using bla::f1();
f1();
}

> And for friends:
>
> class A
> {
> public:
> friend void f2 ();
> };
>
> void b3 ()
> {
> f2 (); // 'f2' not visible
> }
>
> int f2 (); // error: conflicts with 'void f2 ()'

It introduces and ambiguity but not a conflict.

> Hope this explains it.

I really don't think that does explain it.
--
Regards,
Steven

Richard Corden

unread,
Dec 11, 2006, 9:00:09 AM12/11/06
to

Steven T. Hatton wrote:
> Richard Corden wrote:
>
[...]

>> void b2 ()
>> {
>> f1 (); // 'f1' not visible
>> }
>>
>> int f1 (); // error: conflicts with 'void f1 ()'
>
> How so?

There are two namespace functions that only differ in return type.

void f1 ();
int f1();

Most (if not all) compilers seem to get it right to warn for this
example. The fact that 'f1' is declared in block scope does not change
that it is really a namespace function.


I'll grant that my compiler might be wrong, but it certainly
> accepts the following:
>
> //bla.cpp
> #include <iostream>
>
> void b1 () { void f1 (); }
>
> int f1() { return 123; }
>
> int main(){
> b1();
> f1();
> }
>
> c++ -o bla bal.cpp
> Compilation finished at Sun Dec 10 10:41:09
> c++ --version
> g++ (GCC) 4.0.2 20050901 (prerelease) (SUSE Linux)


The compiler is wrong. What's worse, with g++ 4.1.1 both declarations
appear to refer to the same function.

#include <iostream>

void bar ()
{
void f1 ();
f1 ();
}

int f1()
{
std::cout << "Hello" << std::endl;
}

int main(){
bar();
}

> g++ -o t t.cc
> ./t
Hello


> I can come up with a situation in which those declarations are both
> meaningful and used without conflict. For example, I could define
>
> namespace bla {
> void f1() { std::cout << "void bla::f1()"; }
> }
>
> void b1 () {
> void f1 ();
> using bla::f1();
> f1();
> }

I'm not 100% sure what you're example shows here, and I believe it too
is illegal. Take a look at 7.3.3/11 - "...and the declarations do not
declare the same function, the program is ill-formed."


>> And for friends:
>>
>> class A
>> {
>> public:
>> friend void f2 ();
>> };
>>
>> void b3 ()
>> {
>> f2 (); // 'f2' not visible
>> }
>>
>> int f2 (); // error: conflicts with 'void f2 ()'
>
> It introduces and ambiguity but not a conflict.

Yes, g++ uses the word 'ambiguity' in it's message. The important
detail is that the message is an error - so 'conflict' or 'ambiguity' is
not important. Your code won't compile.

>
>> Hope this explains it.
>
> I really don't think that does explain it.

Maybe 2nd time lucky.


Richard

--
Richard Corden

Steven T. Hatton

unread,
Dec 11, 2006, 4:22:03 PM12/11/06
to
Richard Corden wrote:

I guess that's a bug eh? After looking at §7.3.1.2, I have to agree that
the above code is ill-formed, and the compiler(s) are not behaving
correctly.

>
>> I can come up with a situation in which those declarations are both
>> meaningful and used without conflict. For example, I could define
>>
>> namespace bla {
>> void f1() { std::cout << "void bla::f1()"; }
>> }
>>
>> void b1 () {
>> void f1 ();
>> using bla::f1();
>> f1();
>> }
>
> I'm not 100% sure what you're example shows here, and I believe it too
> is illegal. Take a look at 7.3.3/11 - "...and the declarations do not
> declare the same function, the program is ill-formed."

You are correct. I misunderstood the implications of the in-function
declaration of void f1();

>> It introduces and ambiguity but not a conflict.
>
> Yes, g++ uses the word 'ambiguity' in it's message. The important
> detail is that the message is an error - so 'conflict' or 'ambiguity' is
> not important. Your code won't compile.
>
>>
>>> Hope this explains it.
>>
>> I really don't think that does explain it.
>
> Maybe 2nd time lucky.

Well, I believe I understand and agree with your original points. I should
have followed through on my assumptions before I posted. The behavior I
presumed would take place did not, and it should not have.

I have to say that I am confused about the sentence in §7.3.1.2/3 "If a
friend function is called, its name may be found by the name lookup that
considers functions from namespaces and classes associated with the types
of the function arguments (3.4.2)." Taken out of context I would not
question what it means. But given the subsequent sentence, it is not clear
to me if I should understand it to be placing a restriction on the one
quoted above. IOW, will ADL find the definition of a function in another
namespace if the function name is not explicitly qualified?

Here's the complete paragraph:

§7.3.1.2/3 "Every name first declared in a namespace is a member of that
namespace. If a friend declaration in a non-local class first declares a
class or function 83) the friend class or function is a member of the
innermost enclosing namespace. The name of the friend is not found by
simple name lookup until a matching declaration is provided in that
namespace scope (either before or after the class declaration granting
friendship). If a friend function is called, its name may be found by the
name lookup that considers functions from namespaces and classes associated
with the types of the function arguments (3.4.2). When looking for a prior
declaration of a class or a function declared as a friend, and when the
name of the friend class or function is neither a qualified name nor a
template-id, scopes outside the innermost enclosing namespace scope are not
considered."
--
Regards,
Steven

Richard Corden

unread,
Dec 12, 2006, 9:37:33 AM12/12/06
to

Steven T. Hatton wrote:

[...]

> I have to say that I am confused about the sentence in §7.3.1.2/3 "If a
> friend function is called, its name may be found by the name lookup that
> considers functions from namespaces and classes associated with the types
> of the function arguments (3.4.2)." Taken out of context I would not
> question what it means. But given the subsequent sentence, it is not clear
> to me if I should understand it to be placing a restriction on the one
> quoted above. IOW, will ADL find the definition of a function in another
> namespace if the function name is not explicitly qualified?

Ok - The two sentences are unrelated. This part of the paragraph
specifies that the function will be found only by ADL:

namespace NS
{
class A
{
public:
A (int);
friend void foo (A const & a); // is member of NS but not visible
};

void b1 (A const & a)
{
foo (a); // finds 'foo' via ADL *not* normal
// lookup
}

void b2 ()
{
foo (10); // error, 'foo' not found.
}
}

void b3 (NS::A const & a)
{
foo (a); // finds 'foo' via ADL
}


Version 3.4.6 of g++ parses this (incorrectly), but 4.1.1 correctly
catches that 'foo' is undeclared in the call from 'b2'.


>
> Here's the complete paragraph:
>
> §7.3.1.2/3 "Every name first declared in a namespace is a member of that
> namespace. If a friend declaration in a non-local class first declares a
> class or function 83) the friend class or function is a member of the
> innermost enclosing namespace. The name of the friend is not found by
> simple name lookup until a matching declaration is provided in that
> namespace scope (either before or after the class declaration granting
> friendship). If a friend function is called, its name may be found by the
> name lookup that considers functions from namespaces and classes associated
> with the types of the function arguments (3.4.2). When looking for a prior
> declaration of a class or a function declared as a friend, and when the
> name of the friend class or function is neither a qualified name nor a
> template-id, scopes outside the innermost enclosing namespace scope are not
> considered."

The last part of the paragraph controls where we search for the function
when we first declare the friend. ie. what function are we making a
friend of the class.

void f1 (int);

namespace NS
{
void f2 (int);

class A
{
public:
friend void f1 (int); // friend is 'NS::f1' not '::f1'
friend void f2 (int); // friend is 'NS::f2'
};
}

The friend declaration 'friend void f1(int)' is an unqualified
declaration, and so names outside the innermost enclosing namespace, ie.
'::', are not searched. As no 'f1' is found in 'NS', the friend is
considered a declaration of an as of yet invisible function in namespace NS.


Regards,

Richard


--
Richard Corden

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Steven T. Hatton

unread,
Dec 13, 2006, 8:26:44 AM12/13/06
to
Richard Corden wrote:

>
>
> Steven T. Hatton wrote:
>
> [...]

Please let me try to get one point clarified before I address your reply.

This is from TC++PL(SE) §11.5.1:

<quote>

Like a member declaration, a friend declaration *does* *not* *introduce* *a*
*name* into an enclosing scope. For example:

class Matrix{
friend class Xform;
friend Matrix invert(const Matrix&);
};

Xform x; //error: no Xform in scope
Matrix(*p) (const Matrix&)= &invert; //error: no invert() in scope

</quote>

These are from the Standard:

§3.3 #4" ... friend declarations (11.4) *may* *introduce* *a* (possibly not
visible) *name* into an enclosing namespace;.."

§3.3.1 #6"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."

Which of the above statements is applicable to Stroustrup's example? Can
you provide an example of where the statement not applicable to the above
example is applicable?

>> I have to say that I am confused about the sentence in §7.3.1.2/3 "If a
>> friend function is called, its name may be found by the name lookup that
>> considers functions from namespaces and classes associated with the types
>> of the function arguments (3.4.2)." Taken out of context I would not
>> question what it means. But given the subsequent sentence, it is not
>> clear to me if I should understand it to be placing a restriction on the
>> one
>> quoted above. IOW, will ADL find the definition of a function in another
>> namespace if the function name is not explicitly qualified?
>
> Ok - The two sentences are unrelated.

I contend that the wording of the paragraph is inadequate.

> This part of the paragraph
> specifies that the function will be found only by ADL:
>
> namespace NS
> {
> class A
> {
> public:
> A (int);
> friend void foo (A const & a); // is member of NS but not visible
> };

I'm not sure what you mean by that. Do you mean to say that there is a
declaration "somewhere else" of this form?

namespace NS
{
void foo(A const& a);
}

Or do you mean there is a definition of foo in some other namespace which
becomes a member of NS? I believe it is the former, but there are too many
aspects of this problem which I do not yet fully understand for me to draw
a deterministic conclusion.

Of course there will also have to be a /definition/ of void foo(A const& a)
somewhere, assuming foo is called.

I contend that the wording of the paragraph does not clearly communicate
what is intended. Specifically, I understand ADL to be looking for "names
outside the innermost enclosing namespace".

--
Regards,
Steven

Richard Corden

unread,
Dec 13, 2006, 1:45:57 PM12/13/06
to
Steven T. Hatton wrote:

[...]

>
> Please let me try to get one point clarified before I address your reply.
>
> This is from TC++PL(SE) §11.5.1:
>
> <quote>
>
> Like a member declaration, a friend declaration *does* *not* *introduce* *a*
> *name* into an enclosing scope. For example:
>
> class Matrix{
> friend class Xform;
> friend Matrix invert(const Matrix&);
> };
>
> Xform x; //error: no Xform in scope
> Matrix(*p) (const Matrix&)= &invert; //error: no invert() in scope
>
> </quote>
>
> These are from the Standard:
>
> §3.3 #4" ... friend declarations (11.4) *may* *introduce* *a* (possibly not
> visible) *name* into an enclosing namespace;.."
>
> §3.3.1 #6"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."
>
> Which of the above statements is applicable to Stroustrup's example? Can
> you provide an example of where the statement not applicable to the above
> example is applicable?

Firstly, the section quoted from 3.3#4, and also 3.3.1#6 are notes. It
is therefore important to consider them only in connection with the
normative words under 7.3.1.2#3

In 3.3#4, the first part of the sentence included elaborated types which
*do* add names into the enclosing namespace. My impression would be
that "(possibly not visible)" was added to the note so the paragraph
didn't cause confusion with 7.3.1.2. The same more or less applies to
3.3.1#6.

TBH, I don't actually see any conflict with the TC++PL example and the
words of the standard. Neither 'Xform' nor 'invert' are "visible" in
the enclosing namespace. Therefore the type used in the definition of
'x' cannot be found, and neither can the initialiser to the definition
of the function pointer 'p' (ADL only occurs where the postfix
expression of a function call is an unqualified non template-id);


>>> I have to say that I am confused about the sentence in §7.3.1.2/3 "If a
>>> friend function is called, its name may be found by the name lookup that
>>> considers functions from namespaces and classes associated with the types
>>> of the function arguments (3.4.2)." Taken out of context I would not
>>> question what it means. But given the subsequent sentence, it is not
>>> clear to me if I should understand it to be placing a restriction on the
>>> one
>>> quoted above. IOW, will ADL find the definition of a function in another
>>> namespace if the function name is not explicitly qualified?
>> Ok - The two sentences are unrelated.
>
> I contend that the wording of the paragraph is inadequate.

The one thing I've found with the standard is that once I get to
understand a paragraph, it becomes verify difficult to see a better way
to word it that doesn't add in it's own new issues. However, getting to
understand the standard is the problem!


>
>> This part of the paragraph
>> specifies that the function will be found only by ADL:
>>
>> namespace NS
>> {
>> class A
>> {
>> public:
>> A (int);
>> friend void foo (A const & a); // is member of NS but not visible
>> };
>
> I'm not sure what you mean by that. Do you mean to say that there is a
> declaration "somewhere else" of this form?
>
> namespace NS
> {
> void foo(A const& a);
> }
>

Well, yes and no. As you've said below we'll have to define the
function somewhere, so for these examples to link, there eventually will
be a real definition which adds the name to namespace NS. However,
there doesn't need to be....more on that later. :)

> Or do you mean there is a definition of foo in some other namespace which
> becomes a member of NS?

No. For an unqualified friend declaration, when checking what function
is to be made a "friend", lookup only considers the innermost enclosing
namespace. It does not find another definition from an outer scope.

[...]


>
> Of course there will also have to be a /definition/ of void foo(A const& a)
> somewhere, assuming foo is called.

Exactly.

However...you can also have this example:


namespace NS
{
class A
{
public:

friend void foo (A const & a)

{
}
};
}

void bar (NS::A a)
{
foo (a); // OK ADL finds friend
NS::foo (a); // ERROR, 'foo' not declared
}

'foo' is defined in 'A', so there is no need at all to declare or define
'foo' in the namespace NS.


One way of thinking about the visibility of these functions is to
consider the namespace as having 2 sets of names. Normal lookup uses
only the first list, and ADL uses both the first and second list.

namespace NS
{
// NS has [ {<empty>} , {<empty>} ]
class A // NS has [ {A} , {<empty>} ]
{
public:
friend void foo (A const & a) // NS has [ {A} , {foo} ]
{
}
};

void foo (A const & a); // NS has [ {A,foo} , {foo} ]
}

So, in the example above, until we declare 'foo' directly into the
namespace NS, *normal lookup* will only find one name 'A'.

[...]

>>> When looking
>>> for a prior declaration of a class or a function declared as a friend,
>>> and when the name of the friend class or function is neither a qualified
>>> name nor a template-id, scopes outside the innermost enclosing namespace
>>> scope are not considered."

[...]

>
> I contend that the wording of the paragraph does not clearly communicate
> what is intended. Specifically, I understand ADL to be looking for "names
> outside the innermost enclosing namespace".
>

The first part of the sentence states where this sentence applies, ie:
"...for a prior declaration of a class or a function *declared* as a
friend". So, when looking for a prior declaration of a function that
you're declaring as a friend only the innermost enclosing namespace is
checked.

ADL lookup is described in 3.4.2#3, where those 'invisible' functions
are 'visible.


Regards.


--
Richard Corden

Steven T. Hatton

unread,
Dec 13, 2006, 6:50:56 PM12/13/06
to
Richard Corden wrote:

I don't have any reason to understand notes to be non-normative in the
context of the Standard. I believe there are some cases where a feature of
the language is specified entirely in a footnote. In the particular cases
under discussion, it may be possible to glean the actual intent of the
author of the note by examining the referenced sub-clause, but I will still
contend that the wording is inadequate. It could and should be clearer.


> In 3.3#4, the first part of the sentence included elaborated types which
> *do* add names into the enclosing namespace. My impression would be
> that "(possibly not visible)" was added to the note so the paragraph
> didn't cause confusion with 7.3.1.2. The same more or less applies to
> 3.3.1#6.
>
> TBH, I don't actually see any conflict with the TC++PL example and the
> words of the standard. Neither 'Xform' nor 'invert' are "visible" in
> the enclosing namespace. Therefore the type used in the definition of
> 'x' cannot be found, and neither can the initialiser to the definition
> of the function pointer 'p' (ADL only occurs where the postfix
> expression of a function call is an unqualified non template-id);

I can honestly rearrange and abridge the wording to expose the following
meanings from the two statements in question:

"friend declarations *do* *not* *introduce* *new* *names* into that
enclosing namespace."

"friend declarations *may* *introduce* *a* *name* into an enclosing
namespace;"

Those two statements are mutually contradictory.
throw std::logic_error("0==1");


>>>> I have to say that I am confused about the sentence in §7.3.1.2/3 "If a
>>>> friend function is called, its name may be found by the name lookup
>>>> that considers functions from namespaces and classes associated with
>>>> the types
>>>> of the function arguments (3.4.2)." Taken out of context I would not
>>>> question what it means. But given the subsequent sentence, it is not
>>>> clear to me if I should understand it to be placing a restriction on
>>>> the one
>>>> quoted above. IOW, will ADL find the definition of a function in
>>>> another namespace if the function name is not explicitly qualified?
>>> Ok - The two sentences are unrelated.
>>
>> I contend that the wording of the paragraph is inadequate.
>
> The one thing I've found with the standard is that once I get to
> understand a paragraph, it becomes verify difficult to see a better way
> to word it that doesn't add in it's own new issues. However, getting to
> understand the standard is the problem!

I've done OK with several of the Upanishads, The Bhagavad-Gita. The Tao Te
Ching, The Dhammapada, The Hávamál, The Völuspá, etc. I know there are
people who treat C++ as a religion, but I am not willing to accept that a
programming language specification should require the methodology of
ancient and arcane theological scripture. Furthermore, proper translations
of any of the above mentioned texts will not contain overt logical
contradictions.

I believe you probably grasp the intent of the authors of the Standard. I
am not ungrateful for your help in my effort to do the same. I do not
claim that I could write a better language specification. I do, however,
make my share of errors, so I know what they look like, and the above
exposed contradiction looks exactly like an error to me.

I will continue to read the Standard document with the assumption that the
intended meaning will become clear in the sequel.
--
Regards,
Steven

Richard Corden

unread,
Dec 14, 2006, 10:32:59 AM12/14/06
to
Steven T. Hatton wrote:

[...]

> I don't have any reason to understand notes to be non-normative in the


> context of the Standard. I believe there are some cases where a feature of
> the language is specified entirely in a footnote. In the particular cases
> under discussion, it may be possible to glean the actual intent of the
> author of the note by examining the referenced sub-clause, but I will still
> contend that the wording is inadequate. It could and should be clearer.

Notes are 'non-normative'. That is just a fact. If you know of any
sections where the footnote is the only place that feature is specified
then you should post here or to comp.std.c++ and point them out.

Unfortunately, I don't think I can really judge if the section is worded
adequately, since as I say, it's very difficult to go back and read it
without super-imposing my current understanding.

>> In 3.3#4, the first part of the sentence included elaborated types which
>> *do* add names into the enclosing namespace. My impression would be
>> that "(possibly not visible)" was added to the note so the paragraph
>> didn't cause confusion with 7.3.1.2. The same more or less applies to
>> 3.3.1#6.
>>

[...]

> I can honestly rearrange and abridge the wording to expose the following
> meanings from the two statements in question:
>
> "friend declarations *do* *not* *introduce* *new* *names* into that
> enclosing namespace."
>
> "friend declarations *may* *introduce* *a* *name* into an enclosing
> namespace;"
>
> Those two statements are mutually contradictory.
> throw std::logic_error("0==1");

You have a point here, but your second sentence is not a 100% correct
abridgement, specifically you have to add 'possibly not visible'.

"friend declarations may introduce a (possibly not visible) name into an
enclosing namespace;"

So, now the difference is:

"do not introduce new names"

vs


"may introduce a (possibly not visible) name"

As they're written, they're not the *same* but they are not quite at the
level of std::logic_error("0==1") either. In real code, the effect of
both sentences is the same to the developer.

However, based on the wording in 3.4.2/3, where it talks about functions
becoming visible, I think that 3.3.1#6 would be better changed to use
'may introduce a (possibly not visible) name'.

[...]

> ... I am not willing to accept that a


> programming language specification should require the methodology of
> ancient and arcane theological scripture. Furthermore, proper translations
> of any of the above mentioned texts will not contain overt logical
> contradictions.

I agree. I'm not trying to defend the standard for it's ease of use.
Our product uses a home brewed C++ front end and I have spent long hours
trying to understand what the standard is trying to say.

I will defend it on one point however, the people involved in writing
the standard work very hard to remove any overt logical contradictions.

> I believe you probably grasp the intent of the authors of the Standard.

This may be an overstatement. I have however, had the benefit of
speaking to the people involved and asking questions directly.

>
> I will continue to read the Standard document with the assumption that the
> intended meaning will become clear in the sequel.

This is OT, but IMHO the sequel is almost certainly going to have many
more contradictions than the current std. C++ 2003 has had the benefit
of 5 years of bug fixing. The working paper for C++ 0X is missing
wording for some of the larger proposals. Lots of efforts will be made,
but given the time restrictions I think you'll have many opportunities
to highlight 'overt logical contradictions' in the sequel! :)

Regards,

Richard

--
Richard Corden

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Francis Glassborow

unread,
Dec 14, 2006, 11:26:58 AM12/14/06
to
In article <zOmdnQPKV6JB4R3Y...@speakeasy.net>, Steven T.
Hatton <hat...@globalsymmetry.com> writes

>I can honestly rearrange and abridge the wording to expose the following
>meanings from the two statements in question:
>
>"friend declarations *do* *not* *introduce* *new* *names* into that
>enclosing namespace."
>
>"friend declarations *may* *introduce* *a* *name* into an enclosing
>namespace;"
>
>Those two statements are mutually contradictory.
>throw std::logic_error("0==1");


Well the trouble is that in a sense both statements are true :)

We had immense problems with refining the behaviour of friend because we
wanted to avoid injection of names into the enclosing scope but we also
wanted to ensure that we did not break a powerful technique developed by
Barton and Nackman.

The upshot is that:

1) if a name in a friend declaration has already been declared in the
enclosing scope, that is the entity used

2) if the name is subsequently declared in the enclosing scope, that is
the entity used.

(Note that in both cases we have to word things more carefully so as to
deal with the names of overloaded functions)

3) If neither of those cases is true the name will not be found in the
enclosing scope (note that not being found is not the same as not being
there because it can still be found by for example, IIRC, ADL)

Trying to preserve existing practice whilst closing down unwanted name
pollution was, and is, very hard. Even with all the care that went into
it we still managed to make a widely used existing technique invalid.
The words of C++98 make it impossible to grant friendship to a nested
class. We resolved that by making nested classes have access rights to
the private parts of the enclosing class.

The whole issue of names in C++ is a house of cards and it is very easy
to have the whole edifice tumble down if we get some apparently obscure
detail wrong.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Steven T. Hatton

unread,
Dec 14, 2006, 5:38:16 PM12/14/06
to
Francis Glassborow wrote:

> In article <zOmdnQPKV6JB4R3Y...@speakeasy.net>, Steven T.
> Hatton <hat...@globalsymmetry.com> writes
>>I can honestly rearrange and abridge the wording to expose the following
>>meanings from the two statements in question:
>>
>>"friend declarations *do* *not* *introduce* *new* *names* into that
>>enclosing namespace."
>>
>>"friend declarations *may* *introduce* *a* *name* into an enclosing
>>namespace;"
>>
>>Those two statements are mutually contradictory.
>>throw std::logic_error("0==1");
>
>
> Well the trouble is that in a sense both statements are true :)
>
> We had immense problems with refining the behaviour of friend because we
> wanted to avoid injection of names into the enclosing scope but we also
> wanted to ensure that we did not break a powerful technique developed by
> Barton and Nackman.
>
> The upshot is that:
>
> 1) if a name in a friend declaration has already been declared in the
> enclosing scope, that is the entity used

No problem there. The friend declaration comes after the point at which the
name is introduced into the namespace.

> 2) if the name is subsequently declared in the enclosing scope, that is
> the entity used.

This appears to be where the (one) problem arrises. A name declared as a
friend within a class definition is of unclear status between the point of
the friend declaration and the point at which the namespace-local
declaration appears in the immediately enclosing namespace.



> (Note that in both cases we have to word things more carefully so as to
> deal with the names of overloaded functions)
>
> 3) If neither of those cases is true the name will not be found in the
> enclosing scope (note that not being found is not the same as not being
> there because it can still be found by for example, IIRC, ADL)

That may depend on the compiler and the tea leaves consulted by the compiler
writer. I believe a great deal of my inability to reconcile these various
assertions is due to a lack of clarity in the definitions being used. I'm
trying to construct a glossary of terms used in the standard to specify
these features.

The whole problem should be expressible in terms of a finite state machine
which changes state as the lookup proceeds through the token sequence.
According to the Standard, the lookup process will take place prior to
parsing §3/6. Whatever that means. I mention that because I am thinking
in terms of a composite structure in which the translation unit is the
outer-most containing object. Namespaces and other global declarations
would be members of that translation unit object. As each namespace is
processed declarations within it will add components to the corresponding
namespace object. What I am describing seems to be an AST, but my
understanding of what is meant by "parsing" is that it means to build the
AST.

No matter. I am merely talking about a conceptual drawing-board mechanism
which can be used to formalize exactly what happens at every stage of the
name lookup process. When we talk about a friend declaration appearing in
a class definition, we should be able to fully specify the state of the
entire composite at the point immediately following that declaration.
Every component of the composite will have a list of state attributes which
completely determine its state. It should not matter if you call the
attributes visible, valid, defined and type, or John, Paul, George and
Ringo. What matters is that the state is uniquely determined in such as
way as to produced the behavior required by the Standard.

The terms used as attributes of the state machine could then be used to
write the specification. I realize that this is circular, but one must
begin somewhere. We should be able to tack an entire program on the wall,
throw a dart at it, and uniquely describe the state of the composite at the
point where the dart hit.

> Trying to preserve existing practice whilst closing down unwanted name
> pollution was, and is, very hard. Even with all the care that went into
> it we still managed to make a widely used existing technique invalid.
> The words of C++98 make it impossible to grant friendship to a nested
> class. We resolved that by making nested classes have access rights to
> the private parts of the enclosing class.
>
> The whole issue of names in C++ is a house of cards and it is very easy
> to have the whole edifice tumble down if we get some apparently obscure
> detail wrong.

"It must be possible to replace in all geometric statements the words point,
line, plane by table, chair, beer mug." - David Hilbert

--
Regards,
Steven

Steven T. Hatton

unread,
Dec 14, 2006, 5:39:24 PM12/14/06
to
Richard Corden wrote:

> Steven T. Hatton wrote:
>
> [...]
>
>> I don't have any reason to understand notes to be non-normative in the
>> context of the Standard. I believe there are some cases where a feature
>> of the language is specified entirely in a footnote. In the particular
>> cases under discussion, it may be possible to glean the actual intent of
>> the author of the note by examining the referenced sub-clause, but I will
>> still contend that the wording is inadequate. It could and should be
>> clearer.
>
> Notes are 'non-normative'. That is just a fact. If you know of any
> sections where the footnote is the only place that feature is specified
> then you should post here or to comp.std.c++ and point them out.
>
> Unfortunately, I don't think I can really judge if the section is worded
> adequately, since as I say, it's very difficult to go back and read it
> without super-imposing my current understanding.

You might be able to take the two passages I claim to be contradictory, and
devise scenarios which exhibit the behavior described. They try to explain
exactly what it is that differs between saying the identifier is introduced
or not introduced.

I'm wondering if it might be useful to use the term "proposed" rather
than "introduced" in the place where it is stated that the identifier /is/
introduced. I will observe, however, that there is a problem with the
definition of "declaration".

"A declaration (clause 7) *introduces* names into a translation unit or
redeclares names introduced by previous declarations. A declaration
specifies the interpretation and attributes of these names."

So, perhaps, we call it a "friend proclamation"?...

>>> In 3.3#4, the first part of the sentence included elaborated types which
>>> *do* add names into the enclosing namespace. My impression would be
>>> that "(possibly not visible)" was added to the note so the paragraph
>>> didn't cause confusion with 7.3.1.2. The same more or less applies to
>>> 3.3.1#6.
>>>
>
> [...]
>
>> I can honestly rearrange and abridge the wording to expose the following
>> meanings from the two statements in question:
>>
>> "friend declarations *do* *not* *introduce* *new* *names* into that
>> enclosing namespace."
>>
>> "friend declarations *may* *introduce* *a* *name* into an enclosing
>> namespace;"
>>
>> Those two statements are mutually contradictory.
>> throw std::logic_error("0==1");
>
> You have a point here, but your second sentence is not a 100% correct
> abridgement, specifically you have to add 'possibly not visible'.
>
> "friend declarations may introduce a (possibly not visible) name into an
> enclosing namespace;"
>
> So, now the difference is:
>
> "do not introduce new names"
> vs
> "may introduce a (possibly not visible) name"

That's another can'o'worms. Visible is the antonym to hidden. In order for
the name to be hidden, there has to be another name hiding it. But if we
said "a friend proclamation may propose a name..."


> As they're written, they're not the *same* but they are not quite at the
> level of std::logic_error("0==1") either. In real code, the effect of
> both sentences is the same to the developer.
>
> However, based on the wording in 3.4.2/3, where it talks about functions
> becoming visible, I think that 3.3.1#6 would be better changed to use
> 'may introduce a (possibly not visible) name'.
>
> [...]
>
>> ... I am not willing to accept that a
>> programming language specification should require the methodology of
>> ancient and arcane theological scripture. Furthermore, proper
>> translations of any of the above mentioned texts will not contain overt
>> logical contradictions.
>
> I agree. I'm not trying to defend the standard for it's ease of use.
> Our product uses a home brewed C++ front end and I have spent long hours
> trying to understand what the standard is trying to say.
>
> I will defend it on one point however, the people involved in writing
> the standard work very hard to remove any overt logical contradictions.
>

I'm sure that is true. The task of creating something like that is huge.
It's often very difficult to take the extra step of finding another term,
or adding a clarifying comment when you are at the edge of your
understanding and pushing the envelop.

>> I believe you probably grasp the intent of the authors of the Standard.
>
> This may be an overstatement. I have however, had the benefit of
> speaking to the people involved and asking questions directly.

Ur.. they'd probably kill me. :o

>> I will continue to read the Standard document with the assumption that
>> the intended meaning will become clear in the sequel.
>
> This is OT, but IMHO the sequel is almost certainly going to have many
> more contradictions than the current std.

Sorry, I meant the ballance of the existing Standard (clauses 4 to 27).

> C++ 2003 has had the benefit
> of 5 years of bug fixing. The working paper for C++ 0X is missing
> wording for some of the larger proposals. Lots of efforts will be made,
> but given the time restrictions I think you'll have many opportunities
> to highlight 'overt logical contradictions' in the sequel! :)

They need a glossary!
--
Regards,
Steven

Greg Herlihy

unread,
Dec 15, 2006, 8:33:20 AM12/15/06
to
Steven T. Hatton wrote:
> I don't have any reason to understand notes to be non-normative in the
> context of the Standard. I believe there are some cases where a feature of
> the language is specified entirely in a footnote. In the particular cases
> under discussion, it may be possible to glean the actual intent of the
> author of the note by examining the referenced sub-clause, but I will still
> contend that the wording is inadequate. It could and should be clearer.

There is normative text in the Standard that does require that the
(non-normative) text in the footnotes be correct. So I would not read
them as entirely fictional description of the Standard. In other words,
although the footnotes are not normative in their own right, they are,
"once-removed" from normative text. At rate, given all the rules that
appear in the footnotes, I would hope that to be the case.

Steven T. Hatton wrote:
> Richard Corden wrote:

> > In 3.3#4, the first part of the sentence included elaborated types which
> > *do* add names into the enclosing namespace. My impression would be
> > that "(possibly not visible)" was added to the note so the paragraph
> > didn't cause confusion with 7.3.1.2. The same more or less applies to
> > 3.3.1#6.
> >
> > TBH, I don't actually see any conflict with the TC++PL example and the
> > words of the standard. Neither 'Xform' nor 'invert' are "visible" in
> > the enclosing namespace. Therefore the type used in the definition of
> > 'x' cannot be found, and neither can the initialiser to the definition
> > of the function pointer 'p' (ADL only occurs where the postfix
> > expression of a function call is an unqualified non template-id);
>
> I can honestly rearrange and abridge the wording to expose the following
> meanings from the two statements in question:
>
> "friend declarations *do* *not* *introduce* *new* *names* into that
> enclosing namespace."

The emphasis should be on "new" - since a friend declaration may
introduce a name that is not new - to its enclosing namespace.

> "friend declarations *may* *introduce* *a* *name* into an enclosing
> namespace;"

This rule tells us that friend declaration may introduce a name into
its enclosing namespace, and once we incorporate the previous rule into
our reasoning as well, we can conclude that any name that a friend
declaration introduces - may not be a new one.

> Those two statements are mutually contradictory.

No, the crucial distinction being made by the two rules - is whether
the name in the friend declaration is a "new" name within the enclosing
namespace or not. And what is a "new" name exactly? Quite simply it is
a name that would not otherwise exist in that namespace save for the
friend declaration itself. In other words, if there is no other
declaration of that name anywhere in that namespace, then the friend
declaration will not add the name on its own (because the name would be
a "new" name in that namespace.) So unless the friend declaration is
corroborated by another declaration for the same name in the same
namespace, the name in the friend declaration is not "introduced" into
the enclosing namespace.

Now you may ask, if the name in the friend declaration is not "new",
how can a friend declaration "introduce" it? After all, one cannot be
introduced to someone they have already met. The explanation is that
there are two ways that the Standard describes a namespace: the first
is as a linear progression of name declarations, and the other is as a
closed set of names. A friend declaration "introduces" a name at the
point it appears in the namespace and after that point (if the name has
not appeared prior to the friend declaration). It is therefore not a
requirement that the other declaration for the same name appear before
the friend declaration in order for the name to be used after the
friend declaration successfully introduces it. But remember the
introduction does not happen unless there there is matching declaration
that is a member of the namespace's set of names.

> >>>> I have to say that I am confused about the sentence in §7.3.1.2/3 "If a
> >>>> friend function is called, its name may be found by the name lookup
> >>>> that considers functions from namespaces and classes associated with
> >>>> the types
> >>>> of the function arguments (3.4.2)." Taken out of context I would not
> >>>> question what it means. But given the subsequent sentence, it is not
> >>>> clear to me if I should understand it to be placing a restriction on
> >>>> the one
> >>>> quoted above. IOW, will ADL find the definition of a function in
> >>>> another namespace if the function name is not explicitly qualified?

It's the opposite, ADL is only ever applied to when the name of the
function being called is unqualified.

> >>> Ok - The two sentences are unrelated.
> >>
> >> I contend that the wording of the paragraph is inadequate.
> >
> > The one thing I've found with the standard is that once I get to
> > understand a paragraph, it becomes verify difficult to see a better way
> > to word it that doesn't add in it's own new issues. However, getting to
> > understand the standard is the problem!
>
> I've done OK with several of the Upanishads, The Bhagavad-Gita. The Tao Te
> Ching, The Dhammapada, The Hávamál, The Völuspá, etc. I know there are
> people who treat C++ as a religion, but I am not willing to accept that a
> programming language specification should require the methodology of
> ancient and arcane theological scripture. Furthermore, proper translations
> of any of the above mentioned texts will not contain overt logical
> contradictions.
>
> I believe you probably grasp the intent of the authors of the Standard. I
> am not ungrateful for your help in my effort to do the same. I do not
> claim that I could write a better language specification. I do, however,
> make my share of errors, so I know what they look like, and the above
> exposed contradiction looks exactly like an error to me.

The whole point of a Standard is that the intent of its authors should
be irrelevant - the only thing that matters is whatever the Standard
states - because the Standard exists completely within that document.
If any pieces are missing then they do not exist, in particular no
missing pieces of the Standard to be found distributed among the people
who wrote its text.

Greg


--

Francis Glassborow

unread,
Dec 15, 2006, 4:14:41 PM12/15/06
to
In article <dPednYyDHK5PVhzY...@speakeasy.net>, Steven T.
Hatton <hat...@globalsymmetry.com> writes

>That's another can'o'worms. Visible is the antonym to hidden. In order for
>the name to be hidden, there has to be another name hiding it. But if we
>said "a friend proclamation may propose a name..."


How on earth do you reach that conclusion. The words visible and hidden
are being used in their normal plain English meanings. And Even C++ does
not require that a non-visible name be hidden by another (visible) one.
Names declared in other TUs are not visible but that does not mean that
they are being hidden by another declaration of the same name. Names
declared with the static qualifier and in an unnamed namespace are not
visible outside the TU where they are declared, but they are not hidden
(and in the case of names declared in an unnamed namespace, they even
have external linkage)


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Steven T. Hatton

unread,
Dec 16, 2006, 12:08:29 AM12/16/06
to
Francis Glassborow wrote:

> In article <dPednYyDHK5PVhzY...@speakeasy.net>, Steven T.
> Hatton <hat...@globalsymmetry.com> writes
>>That's another can'o'worms. Visible is the antonym to hidden. In order
>>for
>>the name to be hidden, there has to be another name hiding it. But if we
>>said "a friend proclamation may propose a name..."
>
>
> How on earth do you reach that conclusion. The words visible and hidden
> are being used in their normal plain English meanings. And Even C++ does
> not require that a non-visible name be hidden by another (visible) one.

§3.3.7 "If a name is in scope and is not hidden it is said to be visible."

> Names declared in other TUs are not visible but that does not mean that
> they are being hidden by another declaration of the same name. Names
> declared with the static qualifier and in an unnamed namespace are not
> visible outside the TU where they are declared, but they are not hidden
> (and in the case of names declared in an unnamed namespace, they even
> have external linkage)
>
>

--
Regards,
Steven

Steven T. Hatton

unread,
Dec 16, 2006, 12:02:03 AM12/16/06
to
{ Accepted because this moderator does not feel himself competent to
judge the quoting irrelevant, but please don't quote (much) more than
necessary -- as Albert Einstein put it, "in clc++m, quote as much as
necessary to establish proper context, but not more". -mod/aps }

Greg Herlihy wrote:

> Steven T. Hatton wrote:
>> I don't have any reason to understand notes to be non-normative in the
>> context of the Standard. I believe there are some cases where a feature
>> of the language is specified entirely in a footnote. In the particular
>> cases under discussion, it may be possible to glean the actual intent of
>> the author of the note by examining the referenced sub-clause, but I will
>> still contend that the wording is inadequate. It could and should be
>> clearer.
>
> There is normative text in the Standard that does require that the
> (non-normative) text in the footnotes be correct. So I would not read
> them as entirely fictional description of the Standard. In other words,
> although the footnotes are not normative in their own right, they are,
> "once-removed" from normative text. At rate, given all the rules that
> appear in the footnotes, I would hope that to be the case.

I do not believe that one could remove every note from the Standard, hand
the resulting document to another person (regardless of that person's
abilities) and ask him or her to resolve questions which can be resolved by
reading the notes. If the notes were removed, the Standard would not have
the same meaning.

Furthermore, I seriously doubt you could give the Standard to two
excellently qualified experts who have no means of mutual communication and
have both arrive at the same interpretation of the Standard. I don't even
believe Dr. Stroustrup and Dr. Koenig would arrive at the same
interpretation without collaboration.

> Steven T. Hatton wrote:
>> Richard Corden wrote:
>> > In 3.3#4, the first part of the sentence included elaborated types
>> > which
>> > *do* add names into the enclosing namespace. My impression would be
>> > that "(possibly not visible)" was added to the note so the paragraph
>> > didn't cause confusion with 7.3.1.2. The same more or less applies to
>> > 3.3.1#6.
>> >
>> > TBH, I don't actually see any conflict with the TC++PL example and the
>> > words of the standard. Neither 'Xform' nor 'invert' are "visible" in
>> > the enclosing namespace. Therefore the type used in the definition of
>> > 'x' cannot be found, and neither can the initialiser to the definition
>> > of the function pointer 'p' (ADL only occurs where the postfix
>> > expression of a function call is an unqualified non template-id);
>>
>> I can honestly rearrange and abridge the wording to expose the following
>> meanings from the two statements in question:
>>
>> "friend declarations *do* *not* *introduce* *new* *names* into that
>> enclosing namespace."
>
> The emphasis should be on "new" - since a friend declaration may
> introduce a name that is not new - to its enclosing namespace.

Please provide an example of a friend declaration that introduces a name
into a namespace, and then demonstrate how the result of that introduction
differs from the result of a declaration which does /not/ introduce a name
into a namespace.

>> "friend declarations *may* *introduce* *a* *name* into an enclosing
>> namespace;"
>
> This rule tells us that friend declaration may introduce a name into
> its enclosing namespace, and once we incorporate the previous rule into
> our reasoning as well, we can conclude that any name that a friend
> declaration introduces - may not be a new one.

If I introduce the name William Jefferson Clinton into this discussion, am I
introducing a new name?

>> Those two statements are mutually contradictory.
>
> No, the crucial distinction being made by the two rules - is whether
> the name in the friend declaration is a "new" name within the enclosing
> namespace or not. And what is a "new" name exactly? Quite simply it is
> a name that would not otherwise exist in that namespace save for the
> friend declaration itself. In other words, if there is no other
> declaration of that name anywhere in that namespace, then the friend
> declaration will not add the name on its own (because the name would be
> a "new" name in that namespace.) So unless the friend declaration is
> corroborated by another declaration for the same name in the same
> namespace, the name in the friend declaration is not "introduced" into
> the enclosing namespace.

What do you mean by "introduce" and "new"?

> Now you may ask, if the name in the friend declaration is not "new",
> how can a friend declaration "introduce" it? After all, one cannot be
> introduced to someone they have already met. The explanation is that
> there are two ways that the Standard describes a namespace: the first
> is as a linear progression of name declarations, and the other is as a
> closed set of names. A friend declaration "introduces" a name at the
> point it appears in the namespace and after that point (if the name has
> not appeared prior to the friend declaration). It is therefore not a
> requirement that the other declaration for the same name appear before
> the friend declaration in order for the name to be used after the
> friend declaration successfully introduces it. But remember the
> introduction does not happen unless there there is matching declaration
> that is a member of the namespace's set of names.

http://www.dict.org/bin/Dict?Form=Dict2&Database=*&Query=artful


> The whole point of a Standard is that the intent of its authors should
> be irrelevant - the only thing that matters is whatever the Standard
> states - because the Standard exists completely within that document.
> If any pieces are missing then they do not exist, in particular no
> missing pieces of the Standard to be found distributed among the people
> who wrote its text.

--
Regards,
Steven

Francis Glassborow

unread,
Dec 16, 2006, 1:01:50 PM12/16/06
to
In article <C-ednYCx_dvIhR7Y...@speakeasy.net>, Steven T.
Hatton <hat...@globalsymmetry.com> writes

>§3.3.7 "If a name is in scope and is not hidden it is said to be visible."
Hop over to comp.std.c++ and raise a defect because that is clearly an
over-specification (or uses a meaning of visible that needs definition)


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Steven T. Hatton

unread,
Dec 16, 2006, 5:06:09 PM12/16/06
to
Francis Glassborow wrote:

> In article <C-ednYCx_dvIhR7Y...@speakeasy.net>, Steven T.
> Hatton <hat...@globalsymmetry.com> writes
>>§3.3.7 "If a name is in scope and is not hidden it is said to be visible."
> Hop over to comp.std.c++ and raise a defect because that is clearly an
> over-specification (or uses a meaning of visible that needs definition)

I don't recall if I ever registered it as a formal defect, but I have
certainly suggested that terms used to specify C++ should be more clearly
defined. My criticism is not with the fact that a definition _is_ provided
for /visible/ . I want more such definitions. In the limited time I spent
trying to establish a formal glossary based on the meanings given to terms
in the Standard, I came to realize there are several subtle errors. For
example, I believe this statement is wrong:

§3.3.1 #6"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."

A friend declaration can introduce a new valid and visible name into an
enclosing namespace, and that declaration might be the only declaration of
that name.

#include <iostream>
namespace n {
class C {
public:
C():_data("This is an instance of C") {}
friend std::ostream& print(std::ostream& out, const C& c)
{ return out << c._data; }
private:
std::string _data;
};

void fun() {
C c;
print(std::cout, c)<<std::endl;
}
}

int main(){
n::fun();
}

--
Regards,
Steven

Richard Corden

unread,
Dec 18, 2006, 11:48:07 AM12/18/06
to

Steven T. Hatton wrote:
> Francis Glassborow wrote:
>

[...]

>> 3) If neither of those cases is true the name will not be found in the
>> enclosing scope (note that not being found is not the same as not being
>> there because it can still be found by for example, IIRC, ADL)
>
> That may depend on the compiler and the tea leaves consulted by the
compiler
> writer. I believe a great deal of my inability to reconcile these various
> assertions is due to a lack of clarity in the definitions being used. I'm
> trying to construct a glossary of terms used in the standard to specify
> these features.


It is not necessarily because the standard is "confusing" that the
compilers behave as they do.

I have searched through some of the drafts and the May '96 version of
3.3.1#6 has the normative text:

"A function declared as a friend and not previously declared, is
introduced in the smallest enclosing nonclass scope that contains the
friend declaration. "

By September '96, this had changed to the text that is there today.

So, the previous version of the standard declared the names in the
namespace. This was changed in '96 so that the names were only visible
to ADL. Now, the questions are:

1) How much code would have been broken had G++ changed the behaviour?

2) How much "legal" C++ will work because names are made visible to
normal lookup?

I can see a reasonable motivation why G++ would want to keep with it's
previous behaviour.


Richard


--
Richard Corden

Richard Corden

unread,
Dec 18, 2006, 11:46:37 AM12/18/06
to

Steven T. Hatton wrote:

[...]

>
> ... In the limited time I spent


> trying to establish a formal glossary based on the meanings given to terms
> in the Standard, I came to realize there are several subtle errors. For
> example, I believe this statement is wrong:
>
> §3.3.1 #6"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."

I agree that it would be better to change 'they do not introduce new
names' to 'they introduce possibly not visible names'. Or even to scrap
the paragraph completely and let the existing normative text cover the
example.

I am curious to know if 3.3.1#6 was added at a different time to the
other paragraphs, hence the wording nit.


>
> A friend declaration can introduce a new valid and visible name into an
> enclosing namespace, and that declaration might be the only declaration of
> that name.
>
> #include <iostream>
> namespace n {
> class C {
> public:
> C():_data("This is an instance of C") {}
> friend std::ostream& print(std::ostream& out, const C& c)
> { return out << c._data; }
> private:
> std::string _data;
> };
>
> void fun() {
> C c;
> print(std::cout, c)<<std::endl;
> }
> }

Not exactly. 'print' is found by ADL, not by normal lookup.

If you change your example to:

void fun() {
C c;
n::print(std::cout, c)<<std::endl;
}

Now print is no longer found.


The key issue here is that the name is not visible to normal lookup but
is visible to argument dependent lookup.

It is difficult to capture this position 100%. Above in your wording
above you have said they "introduce a new valid and visible name", but
this name is not visible to normal lookup, potentially causing confusion
to someone else.

Richard

--
Richard Corden

0 new messages