About friend declaration

W

WaterWalk

I find friend declaration just very tricky. I tried the following
examples on both MingW(gcc 3.4.2) and VC++ 2005. The results are
surprising.

Example1:
namespace ns1
{
class Test
{
friend void func()
{
printf("func in %s\n", __FILE__);
}
};
}

int main()
{
ns1::func();
}

---End Example1---
gcc: compiles and works
VC++: compile error: 'func': candidate function(s) not accessible

Example2:
-file1.cpp
namespace ns1
{
class Test
{
friend void func();
};
}

int main()
{
ns1::func2("abc");
}

-file2.cpp
namespace ns1
{
void func()
{
printf("func in %s\n", __FILE__);
}
}
---end Example2---
gcc: compiles and works
VC++: compiles and works

I'm rather confused. Does a friend function declaration make it as if
it's also declared in the enclosing namespace? At least in example2,
it seems to be so.

What about Example1? What is the right behavior?
 
C

Christian Hackl

WaterWalk said:
I find friend declaration just very tricky. I tried the following
examples on both MingW(gcc 3.4.2) and VC++ 2005. The results are
surprising.

Example1:
namespace ns1
{
class Test
{
friend void func()
{
printf("func in %s\n", __FILE__);
}
};
}

int main()
{
ns1::func();
}

---End Example1---
gcc: compiles and works

It does not on GCC 4.1.2.

error: 'func' is not a member of 'ns1'
VC++: compile error: 'func': candidate function(s) not accessible

Example2:
-file1.cpp
namespace ns1
{
class Test
{
friend void func();
};
}

int main()
{
ns1::func2("abc");
}

How does "func2" enter the picture here? This cannot compile as it is,
so you obviously did not post the actual code.
 
J

James Kanze

I find friend declaration just very tricky. I tried the
following examples on both MingW(gcc 3.4.2) and VC++ 2005. The
results are surprising.
Example1:
namespace ns1
{
class Test
{
friend void func()
{
printf("func in %s\n", __FILE__);
}

Note that although the function you define is ns1::func, the
declaration for this function is only visible in Test. Since
the function has no parameters, ADL won't enter into effect
either.
int main()
{
ns1::func();

The name shouldn't be visible here.
---End Example1---
gcc: compiles and works

Not with the version I have.
VC++: compile error: 'func': candidate function(s) not accessible

"not visible" would be a better message. Or simply that it
cannot find the function.

Earlier (pre-standard) versions of C++ injected the name of a
friend into the surrounding scope, so some compilers may still
do this for reasons of backwards compatibility.
Example2:
-file1.cpp
namespace ns1
{
class Test
{
friend void func();
};

}
int main()
{
ns1::func2("abc");

I presume you mean ns1::func.
-file2.cpp
namespace ns1
{
void func()
{
printf("func in %s\n", __FILE__);
}
}
---end Example2---
gcc: compiles and works
VC++: compiles and works

This should have the same problem as the above. There is no
declaration of ns1::func visible when you compile main, so the
code shouldn't compile. (Again, the g++ I have here doesn't
compile it. The error message is:
names.cc:20: error: ‘func’ is not a member of ‘ns1’
Not perfect, either: `func' cannot be found in `ns1' would be
better.)
I'm rather confused. Does a friend function declaration make
it as if it's also declared in the enclosing namespace?

No, but it did in pre-standard C++. (More correctly, it
injected the name into file scope---there weren't namespaces ini
pre-standard C++, so there was no namespace scope.)

I forget the reason why the committee changed this. (I've been
told at least a half dozen times. Each time, I recognize that
it is valid, but end up forgetting exactly what it was.) There
was discussion concerning the possibility of breaking existing
code, but in practice, no one could figure out a possible use
for a friend function that didn't have an argument which
depended on the class it was a friend of, and with such an
argument, ADL finds the function, even if the declaration isn't
visible.
 
W

WaterWalk

Note that although the function you define is ns1::func, the
declaration for this function is only visible in Test. Since
the function has no parameters, ADL won't enter into effect
either.


The name shouldn't be visible here.


Not with the version I have.


"not visible" would be a better message. Or simply that it
cannot find the function.

Earlier (pre-standard) versions of C++ injected the name of a
friend into the surrounding scope, so some compilers may still
do this for reasons of backwards compatibility.



I presume you mean ns1::func.


This should have the same problem as the above. There is no
declaration of ns1::func visible when you compile main, so the
code shouldn't compile. (Again, the g++ I have here doesn't
compile it. The error message is:
names.cc:20: error: ‘func’ is not a member of ‘ns1’
Not perfect, either: `func' cannot be found in `ns1' would be
better.)


No, but it did in pre-standard C++. (More correctly, it
injected the name into file scope---there weren't namespaces ini
pre-standard C++, so there was no namespace scope.)

I forget the reason why the committee changed this. (I've been
told at least a half dozen times. Each time, I recognize that
it is valid, but end up forgetting exactly what it was.) There
was discussion concerning the possibility of breaking existing
code, but in practice, no one could figure out a possible use
for a friend function that didn't have an argument which
depended on the class it was a friend of, and with such an
argument, ADL finds the function, even if the declaration isn't
visible.

Thanks for this information. But at the same time, I find some curious
statements in the c++ standard and some books:
c++ standard 3.3/4
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.

c++ standard 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).

To me, they look to say the opposite things. What's more:
C++ Primer, 4th edition, in Chapter 12.5
A friend declaration introduces the named class or nonmember function
into the surrounding scope.

In the same chapter, an example is given:
class X
{
friend class Y;
friend void f();
};

class Z
{
Y *ymem; //ok, declaration for class Y introduced by friend in X
void g() {return ::f();} //ok, declaration of f introduced by X
};

Another source of confusion is how a friend declaration affects name
lookup in the class granting friendship? For example:
class X
{
public:
void show();
Y *py; // is Y visible ?
friend claxx Y
friend void f();
};

void X::show()
{
f(); //is f visible?
}
In X's member function definitions, will f be visible? In X's member
declarations, will Y be visible?

I searched in the standard, but didn't find clues in it's chapters
about name lookup(in 3.4).
 
W

WaterWalk

* WaterWalk:


Thanks for this information. But at the same time, I find some curious
statements in the c++ standard and some books:
c++ standard 3.3/4
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.
c++ standard 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).

Yeah, it's inconsistent.

As far as I can recall there isn't an active issue on it, either.

There should be.

Cheers, & hth.,

I hope so. But maybe I misunderstand some statements in the C++
standard. Not sure.
 
J

James Kanze

* WaterWalk:

[...]
Thanks for this information. But at the same time, I find some curious
statements in the c++ standard and some books:
c++ standard 3.3/4
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.
c++ standard 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).
Yeah, it's inconsistent.
As far as I can recall there isn't an active issue on it, either.
There should be.

Well, both quotes are from non-normative notes; there's no
ambiguity in the normative requirements. But the first one
should definitely be either corrected or dropped. And the
second one seems a bit ambiguous as well to me: a friend
declaration can introduce a new name into a namespace; it just
doesn't make it visible. (But I think that there is a more
general problem of vocabulary here.)
 
J

James Kanze

* WaterWalk:
[...]
Thanks for this information. But at the same time, I find some curious
statements in the c++ standard and some books:
c++ standard 3.3/4
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.
c++ standard 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).
Yeah, it's inconsistent.
As far as I can recall there isn't an active issue on it, either.
There should be.
Well, both quotes are from non-normative notes; there's no
ambiguity in the normative requirements. But the first one
should definitely be either corrected or dropped. And the
second one seems a bit ambiguous as well to me: a friend
declaration can introduce a new name into a namespace; it just
doesn't make it visible. (But I think that there is a more
general problem of vocabulary here.)

While preparing to write up a request for an editorial change
here, I reread the quoted passages in context, and realize that
in context, they are quite clear: the friend declaration
introduces the name into the enclosing namespace, but does not
make it visible there.

This also clears up the question of vocabulary: when the
standard says that a name is "in" a given namespace, that means
that the name (or the entity designated by the name) is a member
of that namespace. When it speaks of scope, it uses the word
visibility or visible. Thus, in the initial example:

namespace NS {
class Foo {
friend void f() ;
} ;
}

The friend declaration introduces the name f into the namespace
NS, but does not make it visible (in scope) in the namespace NS.
In other words, the declaration declares a fully qualified name
::NS::f(), but the declaration is (visible) in the scope of
::NS::Foo.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top