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

Bogus overload-by-retval...

1 view
Skip to first unread message

Risto Lankinen

unread,
May 8, 2007, 10:16:24 AM5/8/07
to

Hi!

Should a conformant C++ compiler compile the following source?

- - -

int f();

struct S
{
friend void f();
};

- - -

Explanation: A "void f()" can never exist when an "int f()" is
already
defined. However, the friend declaration in the example pretends that
it could. Is this a legal reason for the compiler to issue an error
on
the line of said friend declaration?

Cheers!

- Risto -


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

Daniel Krügler

unread,
May 8, 2007, 6:50:31 PM5/8/07
to
On 8 Mai, 16:16, Risto Lankinen <rlank...@gmail.com> wrote:
> Hi!
>
> Should a conformant C++ compiler compile the following source?
>
> - - -
>
> int f();
>
> struct S
> {
> friend void f();
>
> };
>
> - - -
>
> Explanation: A "void f()" can never exist when an "int f()" is
> already
> defined. However, the friend declaration in the example pretends that
> it could. Is this a legal reason for the compiler to issue an error
> on
> the line of said friend declaration?

I would say that this example is already ill-formed:

The friend declared "void f()" is a local declaration
of a non-member function f() in the next-outer scope
because the of 11.4/1:

"A friend of a class is a function or class that is not a member
of the class but is permitted to use the private and protected
member names from the class. The name of a friend is not in
the scope of the class, and the friend is not called with the
member access operators (5.2.5) unless it is a member of
another class."

and has external linkage according to 11.4/3:

"A function first declared in a friend declaration has external
linkage (3.5).[..]"

This in-class friend declaration is only made visible in the
class scope due to 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.[..]"

or more precisely said by 3.3.1/5:

"[..] except as a friend declaration, the identifier is declared
in the smallest non-class, non-function-prototype scope that
contains the declaration.[..]"

Now 7.3.1.2/3 makes it indeed clear, that - although only
visible in the class scope of S - this otherwise behaves like
a normal declaration of a member of the enclosing namespace:

"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 function83) the friend class or function
is a member of the innermost enclosing namespace.[..]"

13.1/1 does not allow the described situation by saying:

"Certain function declarations cannot be overloaded:
- Function declarations that differ only in the return type cannot be
overloaded.[..]"

Greetings from Bremen,

Daniel Krügler

Risto Lankinen

unread,
May 8, 2007, 10:51:54 PM5/8/07
to
On 9 touko, 01:50, Daniel Krügler <daniel.krueg...@googlemail.com>
wrote:

> On 8 Mai, 16:16, Risto Lankinen <rlank...@gmail.com> wrote:
>
> > int f();
>
> > struct S
> > {
> > friend void f();
> > };
>
> I would say that this example is already ill-formed:

Thanks a lot for elaboration. Very much appreciated!

> Now 7.3.1.2/3 makes it indeed clear, that - although only
> visible in the class scope of S - this otherwise behaves like
> a normal declaration of a member of the enclosing namespace:
>
> "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 function83) the friend class or function
> is a member of the innermost enclosing namespace.[..]"

I'm still confused about whether a friend declaration is also
a declaration of the befriended object. Based on 7.3.1.2/3
(quoted above, but not verified), this should compile...

- - -


struct S
{
friend void f();

S()
{
f();
}
};

- - -

... however, Comeau TryItOut online C++ compiler rejects it
(reporting 'f()' as being undefined).

What gives?!?!?

- Risto -

Daniel Krügler

unread,
May 9, 2007, 11:10:25 AM5/9/07
to
On 9 Mai, 04:51, Risto Lankinen <rlank...@gmail.com> wrote:
> On 9 touko, 01:50, Daniel Krügler <daniel.krueg...@googlemail.com>
> wrote:
> > On 8 Mai, 16:16, Risto Lankinen <rlank...@gmail.com> wrote:
>
> > > int f();
>
> > > struct S
> > > {
> > > friend void f();
> > > };
>
> > Now 7.3.1.2/3 makes it indeed clear, that - although only
> > visible in the class scope of S - this otherwise behaves like
> > a normal declaration of a member of the enclosing namespace:
>
> > "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 function83) the friend class or function
> > is a member of the innermost enclosing namespace.[..]"
>
> I'm still confused about whether a friend declaration is also
> a declaration of the befriended object. Based on 7.3.1.2/3
> (quoted above, but not verified), this should compile...
>
> - - -
> struct S
> {
> friend void f();
>
> S()
> {
> f();
> }
>
> };

I was a bit hasty and the following wording was not correct:

"[..] - although only visible in the class scope of S -[..]"

Indeed the standard makes it clear that the friend declaration
is a declaration, which needs a further (non-friend) declaration
to be callable. I found the following sentences which seem
to express this indent:

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

7.3.1.2/3:
"[..] 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.[..]"

This interpretation seems not to be so well-known ;-), because
both VC2005-SP1 and my 3.x mingw compiler do accept the
above code. Following the above expressed reasoning, the code
should be accepted, if written as follows:

struct S {
friend void f();

S();
};

void f(); // Actual declaration to be callable

S::S() {
f();
}

Greetings from Bremen,

Daniel Krügler

--

Vladimir Marko

unread,
May 9, 2007, 4:17:15 PM5/9/07
to
On 9 May, 16:10, Daniel Krügler <daniel.krueg...@googlemail.com>
wrote:

> On 9 Mai, 04:51, Risto Lankinen <rlank...@gmail.com> wrote:
> > - - -
> > struct S
> > {
> > friend void f();
>
> > S()
> > {
> > f();
> > }
>
> > };
> ...

>
> 7.3.1.2/3:
> "[..] 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.[..]"
>
> This interpretation seems not to be so well-known ;-), because
> both VC2005-SP1 and my 3.x mingw compiler do accept the
> above code. ...

gcc acknowledged this as a bug long ago and it was fixed in
recent releases. I just tested that gcc 4.1.2 [source->cygwin]
indeed refuses the code.

Regards
Vladimir Marko

0 new messages