sign in | join about | help | sitemap
Connecting Tech Pros Worldwide
Andrey Tarasevich's Avatar

Friends again... (no templates :)


Question posted by: Andrey Tarasevich (Guest) on February 1st, 2007 11:15 PM
Hello

Consider the following code fragment

namespace N {
struct S {
void foo();
};
}

using namespace N; // 1

class C {
friend struct S; // 2
C() {}
};

void N::S::foo() {
C c; // 3 Is C's constructor accessible here???
}

According to what I can see in the standard, friend declaration at point
2 is supposed to perform name lookup for unqualified name 'S' in order
to determine whether this is the first declaration of 'S'. According to
7.3.1.2/3, the lookup goes up to the innermost enclosing namespace scope
(which happens to be the global scope in this case). According to
3.4.1/2, name 'S' introduced by a using directive at point 1 is
considered to be a member of global namespace for the purposes of
unqualified name lookup. This makes me to conclude that the friend
declaration at 2 is supposed to refer to 'N::S' instead of introducing a
new [hidden] declaration of 'struct S' into the global namespace. I.e.
the constructor of 'C' is supposed to be accessible at point 3.

Experiments show that GCC 3.3.3 accepts the code. So does MSVC++ 2005
(for what it's worth). But Comeau Online rejects it, complaining that
the constructor is inaccessible at 3. I just found out that GCC 4.1 also
refuses to compile this code for the same reason.

Did something change in the language specification recently? Something
that applies in this case?

--
Best regards,
Andrey Tarasevich
6 Answers Posted
Greg Herlihy's Avatar
Guest - n/a Posts
#2: Re: Friends again... (no templates :)

On 2/1/07 3:06 PM, in article Join Bytes!, "Andrey
Tarasevich" <andreytarasevich@hotmail.comwrote:
Quote:
Originally Posted by
Consider the following code fragment
>
namespace N {
struct S {
void foo();
};
}
>
using namespace N; // 1
>
class C {
friend struct S; // 2
C() {}
};
>
void N::S::foo() {
C c; // 3 Is C's constructor accessible here???
}
>
According to what I can see in the standard, friend declaration at point
2 is supposed to perform name lookup for unqualified name 'S' in order
to determine whether this is the first declaration of 'S'. According to
7.3.1.2/3, the lookup goes up to the innermost enclosing namespace scope
(which happens to be the global scope in this case). According to
3.4.1/2, name 'S' introduced by a using directive at point 1 is
considered to be a member of global namespace for the purposes of
unqualified name lookup. This makes me to conclude that the friend
declaration at 2 is supposed to refer to 'N::S' instead of introducing a
new [hidden] declaration of 'struct S' into the global namespace. I.e.
the constructor of 'C' is supposed to be accessible at point 3.


A using directive like the one above ("using namespace N") does not
"introduce" any names into the declarative region in which the directive
appears. Instead, a using directive merely affects how names are looked up
within that declarative region.

Since a friend declaration requires that the named friend (S in this case)
be a member of the enclosing declarative region (if the friend is to be
found there), a using directive is not enough in this case for the compiler
to find the intended friend class: N::S.

Since a using declaration does introduce a name into its enclosing region,
it is possible to fix this problem by using a using declaration instead of
using a using directive to bring the name S into the proper declarative
region. For example:

using N::S; // 1

class C
{
friend struct S; // 2
C() {}
};

Greg

Sumit Rajan's Avatar
Guest - n/a Posts
#3: Re: Friends again... (no templates :)

Andrey Tarasevich wrote:
Quote:
Originally Posted by
Hello
>
Consider the following code fragment
>
namespace N {
struct S {
void foo();
};
}
>
using namespace N; // 1
>
class C {
friend struct S; // 2


public:
Quote:
Originally Posted by
C() {}
};
>
void N::S::foo() {
C c; // 3 Is C's constructor accessible here???
}


Comeau should now be able to compile it.

Regards,
Sumit.
Sumit Rajan's Avatar
Guest - n/a Posts
#4: Re: Friends again... (no templates :)

Sumit Rajan wrote:
Quote:
Originally Posted by
Andrey Tarasevich wrote:
Quote:
Originally Posted by
>Hello
>>
>Consider the following code fragment
>>
> namespace N {
> struct S {
> void foo();
> };
> }
>>
> using namespace N; // 1
>>
> class C {
> friend struct S; // 2

>
public:
>
Quote:
Originally Posted by
> C() {}
> };
>>
> void N::S::foo() {
> C c; // 3 Is C's constructor accessible here???
> }

>
Comeau should now be able to compile it.



Oops! Should've paid more attention. Please disregard my previous post.

Sumit.
Andrey Tarasevich's Avatar
Andrey Tarasevich February 2nd, 2007 08:45 AM
Guest - n/a Posts
#5: Re: Friends again... (no templates :)

Greg Herlihy wrote:
Quote:
Originally Posted by
>
Quote:
Originally Posted by
>Consider the following code fragment
>>
> namespace N {
> struct S {
> void foo();
> };
> }
>>
> using namespace N; // 1
>>
> class C {
> friend struct S; // 2
> C() {}
> };
>>
> void N::S::foo() {
> C c; // 3 Is C's constructor accessible here???
> }
>>
>According to what I can see in the standard, friend declaration at point
>2 is supposed to perform name lookup for unqualified name 'S' in order
>to determine whether this is the first declaration of 'S'. According to
>7.3.1.2/3, the lookup goes up to the innermost enclosing namespace scope
>(which happens to be the global scope in this case). According to
>3.4.1/2, name 'S' introduced by a using directive at point 1 is
>considered to be a member of global namespace for the purposes of
>unqualified name lookup. This makes me to conclude that the friend
>declaration at 2 is supposed to refer to 'N::S' instead of introducing a
>new [hidden] declaration of 'struct S' into the global namespace. I.e.
>the constructor of 'C' is supposed to be accessible at point 3.

>
A using directive like the one above ("using namespace N") does not
"introduce" any names into the declarative region in which the directive
appears.


Yes, it does "virtually" introduce the names into the region
("virtually" here means that the names are introduced for the purpose of
name lookup only). That is exactly what 3.4.1/2 says:

"For the purpose of of the unqualified name lookup rules described in
3.4.1, the declarations from the namespace nominated by the
'using-directive' are considered members of that enclosing namespace."
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Quote:
Originally Posted by
Instead, a using directive merely affects how names are looked up
within that declarative region.


Well, that is exactly _how_ in affects the lookup process. By
introducing the names into the region _as_ _members_ (for the purposes
of unqualified name lookup only).
Quote:
Originally Posted by
Since a friend declaration requires that the named friend (S in this case)
be a member of the enclosing declarative region (if the friend is to be
found there), a using directive is not enough in this case for the compiler
to find the intended friend class: N::S.


The standard does not agree with you on that. Once again, it literally
says that in the above example for the purposes of unqualified name
lookup name 'S' (standing for 'N::S') is considered a member of global
namespace.
Quote:
Originally Posted by
Since a using declaration does introduce a name into its enclosing region,
it is possible to fix this problem by using a using declaration instead of
using a using directive to bring the name S into the proper declarative
region. For example:
>
using N::S; // 1
>
class C
{
friend struct S; // 2
C() {}
};


This will cause at least Comeau Online to issue a different error - at
point 2 it will say that name 'S' has already been declared in this
scope. It is the same problem as in

namespace N { struct S {}; }

using N::S;
struct S {}; // ERROR: 'S' has already been declared

Apparently, in your modified example Comeau still refuses to link friend
declaration to 'N::S'. I might look into that separately later, but at
this time I'm primarily interested in the original version with using
directive.

--
Best regards,
Andrey Tarasevich

Andrey Tarasevich's Avatar
Andrey Tarasevich February 2nd, 2007 09:25 AM
Guest - n/a Posts
#6: Re: Friends again... (no templates :)

Andrey Tarasevich wrote:
Quote:
Originally Posted by
...
Did something change in the language specification recently? Something
that applies in this case?
...


OK, it looks like it all comes from here

http://www.open-std.org/jtc1/sc22/w...active.html#138
http://www.open-std.org/jtc1/sc22/w...2000/n1229.html

It all still appears to be in the drafting stage, but according to the
recommendations section in 'n1229' using directives should not be
considered by name lookup performed for friend declarations. In other
words, Comeau Online and GCC 4.1 do indeed violate the requirements of
the current language specification by implementing on of the possible
future changes in it (a bit prematurely, I'd say).

--
Best regards,
Andrey Tarasevich

Andrey Tarasevich's Avatar
Andrey Tarasevich February 2nd, 2007 06:15 PM
Guest - n/a Posts
#7: Re: Friends again... (no templates :)

Andrey Tarasevich wrote:
Quote:
Originally Posted by
...


It looks like the situation with correct support of "friends" is pretty
grim even when it comes to simpler cases. In the following code

struct B { void foo(); };

namespace X {
class A {
A() {}
friend struct B; // refers to X::B, not to ::B
};

struct B {
void foo();
};
}

void X::B::foo() {
X::A a; // OK
}

void B::foo() {
X::A a; // ERROR
}

compilers are supposed to accept the 'OK' line and reject the 'ERROR'
one. In practice so far I only found that Comeau Online and Forte
Developer 7 C++ 5.4 behave properly. MS C++ compilers (including 2005),
GCC 3 get it wrong. And that despite the fact that the standard even has
a specific example dedicated to this situation in 7.3.1.2/3...

--
Best regards,
Andrey Tarasevich
 
Not the answer you were looking for? Post your question . . .
197,004 members ready to help you find a solution.
Join Bytes.com

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over 197,004 network members.
Post your question now . . .
It's fast and it's free

Popular Articles

Top Community Contributors