friend and unnamed namespace

I

Ivan Mascovich

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?
 
A

Alf P. Steinbach

* 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.
 
V

Victor Bazarov

Ivan said:
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
 
V

Victor Bazarov

Alf said:
* Ivan Mascovich:



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.
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.
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
 
A

Alf P. Steinbach

* Victor Bazarov:
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.


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.

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.
 
V

Victor Bazarov

Alf said:
[..]
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
 
P

Pete Becker

Alf said:
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; }
 
A

Alf P. Steinbach

* Victor Bazarov:
Alf said:
[..]
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

Alf P. Steinbach

* 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?
 
V

Victor Bazarov

Alf said:
[..]
"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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top