By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,307 Members | 2,120 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,307 IT Pros & Developers. It's quick & easy.

friend and unnamed namespace

P: n/a
Previous posts (and compilers) confirm that

class X
{
friend void Y() ;
} ;

does not match

namespace
{
void y ()
{
}

}

Is there any way to declare the friend such that it will match a function
in an unnamed namespace --- OR does one simply have to do things the old
way with static?
Mar 2 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
* Ivan Mascovich:
Previous posts (and compilers) confirm that

class X
{
friend void Y() ;
} ;

does not match

namespace
{
void y ()
{
}

}
Well, it can't, because Y and y are two different names.

But if you use the same function name (et cetera), then yes, there's no
way to forward-declare a function in an anonymous namespace outside of
that namespace, because each anonymous namespace is a different
namespace, and can't be referred to.

Is there any way to declare the friend such that it will match a function
in an unnamed namespace
Not in any useful way, no (if you have the anonyous namespace before the
class definition it rather defeats the purpose).

--- OR does one simply have to do things the old way with static?


static is good, whether you mean a namespace scope static function, or a
static member function; the first restricts access to this translation
unit, and the second can restrict access to this class.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Mar 3 '06 #2

P: n/a
Ivan Mascovich wrote:
Previous posts (and compilers) confirm that

class X
{
friend void Y() ;
} ;

does not match

namespace
{
void y ()
{
}

}
First of all, 'Y' and 'y' are different names in C++.
Is there any way to declare the friend such that it will match a function
in an unnamed namespace --- OR does one simply have to do things the old
way with static?


There is no way. Take a look:
------------------------------------------
class A;
namespace NS {
int Y(A*);
}

using namespace NS;

int y = Y(0);

class A {
int a;
friend int NS::Y(A*); /////////// *****************
};

namespace NS {
int Y(A* pa) {
return pa->a;
}
}

int main() {
A a;
Y(&a);
}
-----------------------------------------

Imagine that 'NS' does not exist, but is replaced with some unique to your
translation unit identifier. That's what essentially happens when you
create an unnamed namespace. Now, notice that if you remove the 'NS::'
from the 'friend' declaration in 'class A', the friend declaration will
_introduce_ the name 'Y' into the _global_ namespace. Then the program
will be ill-formed due to two reasons: access to 'a' member in 'Y' is not
granted and in 'main' the call to 'Y' is ambiguous.

That's the problem with 'friend' declarations, not with unnamed namespaces
and the way to combat it would be either name your namespace and use the
name in the 'friend' as well, or (temporarily, until your compiler stops
supporting those) use 'static'. The use of 'static' for declaring any
functions you don't want other modules to see has been deprecated.

V
--
Please remove capital As from my address when replying by mail
Mar 3 '06 #3

P: n/a
Alf P. Steinbach wrote:
* Ivan Mascovich:
Previous posts (and compilers) confirm that

class X
{
friend void Y() ;
} ;

does not match

namespace
{
void y ()
{
}

}

Well, it can't, because Y and y are two different names.

But if you use the same function name (et cetera), then yes, there's no
way to forward-declare a function in an anonymous namespace outside of
that namespace, because each anonymous namespace is a different
namespace, and can't be referred to.


That's not true. You can forward-declare any function in an unnamed
namespace in the _same_ translation unit. The problem is that forward-
declaring it does not help.
Is there any way to declare the friend such that it will match a
function in an unnamed namespace

Not in any useful way, no (if you have the anonyous namespace before the
class definition it rather defeats the purpose).


No. The problem in the way 'friend' works, not in the way unnamed
namespaces work.
> --- OR does one simply have to do things the old way with static?


static is good, whether you mean a namespace scope static function, or a
static member function; the first restricts access to this translation
unit, and the second can restrict access to this class.


A static member of the same class has all access it needs, there is no
need to declare it a friend.

V
--
Please remove capital As from my address when replying by mail
Mar 3 '06 #4

P: n/a
* Victor Bazarov:
Alf P. Steinbach wrote:
* Ivan Mascovich:
Previous posts (and compilers) confirm that

class X
{
friend void Y() ;
} ;

does not match

namespace
{
void y ()
{
}

}

Well, it can't, because Y and y are two different names.

But if you use the same function name (et cetera), then yes, there's
no way to forward-declare a function in an anonymous namespace outside
of that namespace, because each anonymous namespace is a different
namespace, and can't be referred to.


That's not true. You can forward-declare any function in an unnamed
namespace in the _same_ translation unit.


In practice, with current compilers, that seems to be the case, yes.

However, the standard seems quite clear when it /syntactically/ reserves
the mechanism of namespace extension to named namespaces

And requires every anonymous namespace (not making any distiction
between "in the same translation unit" or otherwise) to behave as if it
had a globally unique name.

Which would make it different to declare a function in one anonymous
namespace and define it in another, even in the same translation unit.

Perhaps you could cite the relevant part of the standard that allows an
anonymous namespace to be extended (in the same translation unit)?

The problem is that forward- declaring it does not help.
Is there any way to declare the friend such that it will match a
function in an unnamed namespace

Not in any useful way, no (if you have the anonyous namespace before
the class definition it rather defeats the purpose).


No. The problem in the way 'friend' works, not in the way unnamed
namespaces work.


Again, that seems to be the case in practice, with current compilers.

However, again I'm afraid I must ask for language in the standard that
supports that view.

It may be that I'm blind on both eyes, but it may be that we're on the
trail of not just one but two different defects in the standard.

> --- OR does one simply have to do things the old way with static?


static is good, whether you mean a namespace scope static function, or
a static member function; the first restricts access to this
translation unit, and the second can restrict access to this class.


A static member of the same class has all access it needs, there is no
need to declare it a friend.


That's right, that's why the OP mentioned it as an alternative.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Mar 3 '06 #5

P: n/a
Alf P. Steinbach wrote:
[..]
Perhaps you could cite the relevant part of the standard that allows
an anonymous namespace to be extended (in the same translation unit)?

I am not going to cite it. Open it on page 115 and read 7.3.1.1.
Pay special attention to the words "where _all_ occurrences..."
(emphasis mine).
[..]


V
--
Please remove capital As from my address when replying by mail
Mar 3 '06 #6

P: n/a
Alf P. Steinbach wrote:

However, the standard seems quite clear when it /syntactically/ reserves
the mechanism of namespace extension to named namespaces
Well, "reserves" is a bit strong. Yes, there are two grammar
productions, one for an unnamed-namespace-definition, and one for an
unnamed-namespace-extension. The obvious purpose of that distinction is
to be able to say that the name of an unnamed-namespace-extension must
have been the name in a prior unnamed-namespace-definition. I'd be leary
of reading more subtle implications into that.

And requires every anonymous namespace (not making any distiction
between "in the same translation unit" or otherwise) to behave as if it
had a globally unique name.


On the contrary: 7.3.1/1 says

An unnamed-namespace-definition behaves as if it
were replaced by

namespace unique { /* empty body */ }
using namespace unique;
namespace unique { namespace-body }
where all occurrences of 'unique' IN A
TRANSLATION UNIT are replaced by the same identifier
and this identifier differs from all other identifiers
in the entire program. [emphasis added]

Now, certainly, the following is valid:

namespace x { /* empty body */ } // definition
using namespace x;
namespace x { int i; } // extension

namespace x { /* empty body */ } // extension
using namespace x;
namespace x { int j; } // extension

and if you replace 'x' by 'unique' that's what you get from

namespace { int i; }
namespace { int j; }

--

Pete Becker
Roundhouse Consulting, Ltd.
Mar 3 '06 #7

P: n/a
* Victor Bazarov:
Alf P. Steinbach wrote:
[..]
Perhaps you could cite the relevant part of the standard that allows
an anonymous namespace to be extended (in the same translation unit)?


I am not going to cite it. Open it on page 115 and read 7.3.1.1.
Pay special attention to the words "where _all_ occurrences..."
(emphasis mine).


Yep, you're right about that.

That leaves the second part I addressed in that posting, your statement

"Now, notice that if you remove the 'NS::' from the 'friend'
declaration in 'class A', the friend declaration will _introduce_ the
name 'Y' into the _global_ namespace."

Yes, that's how current compilers behave, but finding that in the
standard is beyond me.

3.3/4 says a friend declaration "may introduce a (possibly not visible)
name into an enclosing namespace".

3.3.1/6 contrariwise says friend declarations "do not introduce new
names into [the nearest enclosing namespace]".

7.3.1.2/3 is perhaps the one nearest to saying what you say (and
current compilers do), namely that

"If a friend declaration in a non-local class first declares a class
or function[note 83] the friend class or function is a member of the
innermost enclosing namespace."

where note 83 is "this implies that the name of the class or function is
unqualified".

A using-declaration is a declaration, so

using SomeNameSpace::foo;

should suffice as a pre-declaration of foo() in the namespace enclosing
the class -- but it does not, with current compilers.

11.4/7, in the "Friends" section, requires that

"A name nominated by a friend declaration shall be accessible in the
scope of the class containing the friend declaration"

And there is no other requirement, as far as I can see.

Is there perhaps something I have overlooked?

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Mar 3 '06 #8

P: n/a
* Pete Becker:
where all occurrences of 'unique' IN A
TRANSLATION UNIT are replaced by the same identifier
and this identifier differs from all other identifiers
in the entire program. [emphasis added]


Yep, thanks!

I may have to invest in new glasses... ;-)

Perhaps there's something I likewise simply don't see (before it's
pointed out) regarding the effect of unqualified names in friend
function declarations; I'm aware of 7.3.1.2/3, but what I'm able to see
of it -- heh -- doesn't seem to preclude something like

namespace ANameSpace{ void x(); }
using ANameSpace::x; // If this isn't 'first declared', then
// a 'void x() {}' here should compile?

class Foo
{
friend void x();
};

with the definition of ANameSpace::x then having friendship status (yes,
I know that's not how current compilers work).

What I do see is that 11.4/7 requires that

"A name nominated by a friend declaration shall be accessible in the
scope of the class containing the friend declaration"

and 'void x()' is accessible, isn't it?

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Mar 3 '06 #9

P: n/a
Alf P. Steinbach wrote:
[..]
"Now, notice that if you remove the 'NS::' from the 'friend'
declaration in 'class A', the friend declaration will _introduce_ the
name 'Y' into the _global_ namespace."

Yes, that's how current compilers behave, but finding that in the
standard is beyond me.

3.3/4 says a friend declaration "may introduce a (possibly not visible)
name into an enclosing namespace".

3.3.1/6 contrariwise says friend declarations "do not introduce new
names into [the nearest enclosing namespace]".
That's in a "Note", which is non-normative.
7.3.1.2/3 is perhaps the one nearest to saying what you say (and
current compilers do), namely that

"If a friend declaration in a non-local class first declares a class
or function[note 83] the friend class or function is a member of the
innermost enclosing namespace."

where note 83 is "this implies that the name of the class or function is
unqualified".

A using-declaration is a declaration, so

using SomeNameSpace::foo;

should suffice as a pre-declaration of foo() in the namespace enclosing
the class -- but it does not, with current compilers.
'using' declaration like that does not make 'foo' a _member_ [of the
global, I presume, namespace], it just makes it _resolvable_.
11.4/7, in the "Friends" section, requires that

"A name nominated by a friend declaration shall be accessible in the
scope of the class containing the friend declaration"

And there is no other requirement, as far as I can see.

Is there perhaps something I have overlooked?


Maybe. AFA I'm concerned, this is one of the most convoluted and unclear
parts of the language, which suggests that declaring anything as 'friend'
should be generally avoided.

V
--
Please remove capital As from my address when replying by mail
Mar 3 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.