Topic: Defect Report: Friend declarations and using-declarations


Author: wmm@fastdial.net
Date: 1999/07/25
Raw View
In article <p6q7lnutghb.fsf@pandora.inst-inf-1.hu-berlin.de>,
  Martin von Loewis <loewis@informatik.hu-berlin.de> wrote:
> fvali@biotrack.com writes:
>
> > I would interpret this fragment unambiguously as well-formed
according
> > to 7.3.3 Paragraphs 1 and 3, which pretty much say that using
> > declarations are tantamount to declarations in the scope in which
they
> > are used, even though they may be perceived as 'synonyms' for other
> > declarations.
>
> Well, paragraph 3 says that the using-declaration is a
> member-declaration, not that the entities referred-to by the
> using-declaration are members of the namespace.

The referred-to entities certainly do not become members of the
namespace containing the using-declaration, but I believe they
do declare those entities in that namespace.

> If the functions really *where* members, then the following would be
> ill-formed:
>
> namespace A{long foo(){}}
> namespace B{void foo(){}}
> namespace C{
>   using A::foo;
>   using B::foo;
> }
>
> This "declares" two member functions into namespace C; A::foo and
> B::foo. Now, according to 8.3.5, [dcl.fct]/3, this would be
> ill-formed, right?
>
> >> A single name can be used for several different functions in a
> >> single scope; this is function overloading (clause 13). All
> >> declarations for a function with a given parameter list shall agree
> >> exactly both in the type of the value returned and in the number
> >> and type of parameters; the presence or absence of the ellipsis is
> >> considered part of the function type.
>
> We have two declarations for the single name foo with no parameters;
> one that returns long, and one that returns void, in the single scope
> C.
>
> However, I believe that the intention of the committee was that the
> above example is well-formed. The only conclusion is that
> using-declarations *do not* declare the functions in the namespace.

It's clear from the note in 7.3.3p11 that this is well-formed (as
long as you don't write an expression that is resolved by overload
resolution to both functions).

I disagree with your conclusion, though.  As I understand it, the
two functions _are_ declared in the namespace, but they do not lose
the fact that they are members of different namespaces.  Thus they
do not conflict.

In point of fact, this relaxation of the rules against conflicting
declarations in the same namespace, when introduced by using-
declarations, is simply because the alternative would have made
using-declarations less useful.  Because a using-declaration gives
just the name, not the signature, of a function, it's quite possible
that conflicting declarations may be introduced, with no way of
avoiding the conflict.  The relaxation of the rule allows the user
to write the using-declarations anyway, as long as there's no need
to resolve the ambiguity.

I'd also point out that the the following _is_ ill-formed:

 namespace N {
     void f();
 }
 void f();
 using N::f;

Using your argument, if the using-declaration isn't a function
declaration, why is this a conflict?

--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: 1999/07/28
Raw View

[ISO C++ says]

>> All declarations for a function with a given parameter list shall
>> agree

wmm@fastdial.net writes:

> I disagree with your conclusion, though.  As I understand it, the
> two functions _are_ declared in the namespace, but they do not lose
> the fact that they are members of different namespaces.  Thus they
> do not conflict.

Well, then the rule about conflicts declarations should exclude using
declarations, but it doesn't. IMHO, it doesn't have to - a using
declarations does not, in my understanding, declare the functions in
the namespace.

> I'd also point out that the the following _is_ ill-formed:
>
>  namespace N {
>      void f();
>  }
>  void f();
>  using N::f;
>
> Using your argument, if the using-declaration isn't a function
> declaration, why is this a conflict?

Because 7.3.3/11 explicitly says so. This is an additional
well-formedness condition, which is violated by your example.

Please note that this condition says that N::f is "introduced" in the
global namespace, not that it is "declared" there. I view this as a
deliberate formulation, not as an accident. Out of curiosity: who of
the committee experts drafted that text in the first place?

I feel that this strengthens my point. If functions named in a
using-declaration where indeed declared in the namespace of the
using-declaration, this well-formedness rule would automatically
follow. OTOH, the reverse statement (using-declarations do not
conflict with each other) is only a Note, so the author apparently
felt that it automatically follows.

Of course, this well-formedness condition is there for a purpose:
Otherwise, you would have no way to call ::f. In C++, nothing is
hidden "for good"; you can always explicitly qualify. Removing the
condition in /11, this "design principle" would be violated.

Regards,
Martin



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: fvali@biotrack.com
Date: 1999/07/20
Raw View
In article <p6qu2r9gei0.fsf@pandora.inst-inf-1.hu-berlin.de>,
  Martin von Loewis <loewis@informatik.hu-berlin.de> wrote:

>
> According to 7.3.1.2, [namespace.memdef]/3, a friend declaration
> declares a new namespace member if that is the *first* declaration.
> It also says that namespaces other than the enclosing are not
> considered in looking for a prior declaration. This text is ambiguous
> in the presence of using-declarations:
>
> void foo();
> namespace A{
>   using ::foo;
>   class X{
>     friend void foo();
>   };
> };
>
I would interpret this fragment unambiguously as well-formed according
to 7.3.3 Paragraphs 1 and 3, which pretty much say that using
declarations are tantamount to declarations in the scope in which they
are used, even though they may be perceived as 'synonyms' for other
declarations.

regards,
-fais
I included the original poster's interpretations for reference -

> This fragment could be interpreted as well-formed, since the friend
> declaration in class X considers the enclosing namespace, finds the
> using-declaration, and then declares ::foo as a friend of A::X.
>
> Alternatively, this fragment could be interpreted as
> ill-formed. Lookup in the enclosing namespace does not find a prior
> declaration of foo (in that namespace), therefore, this is the first
> declaration of void foo(void) in ::A. This would then be ill-formed
> according to 7.3.3, [namespace.udecl]/11.
>



Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: wmm@fastdial.net
Date: 1999/07/20
Raw View
In article <7n0bkk$b65$1@nnrp1.deja.com>,
  fvali@biotrack.com wrote:
> In article <p6qu2r9gei0.fsf@pandora.inst-inf-1.hu-berlin.de>,
>   Martin von Loewis <loewis@informatik.hu-berlin.de> wrote:
>
> >
> > According to 7.3.1.2, [namespace.memdef]/3, a friend declaration
> > declares a new namespace member if that is the *first* declaration.
> > It also says that namespaces other than the enclosing are not
> > considered in looking for a prior declaration. This text is
ambiguous
> > in the presence of using-declarations:
> >
> > void foo();
> > namespace A{
> >   using ::foo;
> >   class X{
> >     friend void foo();
> >   };
> > };
> >
> I would interpret this fragment unambiguously as well-formed according
> to 7.3.3 Paragraphs 1 and 3, which pretty much say that using
> declarations are tantamount to declarations in the scope in which they
> are used, even though they may be perceived as 'synonyms' for other
> declarations.

An alternative position (which I do not personally hold, but which is
implemented in one of the major compilers on the market) agrees with
your understanding of using-declarations but says that a friend
declaration of an unqualified function name _always_ declares a
member of its immediately-containing namespace -- even though the name
is invisible unless explicitly declared in the namespace scope, the
declaration is nevertheless injected into the namespace.  Consequently,
according to this interpretation, the program fragment is ill-formed
by virtue of 7.3.3p11: "If a function declaration in namespace scope
or block scope has the same name and the same parameter types as a
function introduced by a using-declaration, the program is ill-formed."

In other words, the friend declaration declares A::foo(), and the
using-declaration of ::foo() in namespace A cannot coexist with
A::foo().  According to this view, the "lookup" for the name in a
friend declaration isn't really a lookup at all, it's just a
determination whether a declaration is a redeclaration of an already-
declared entity or not, so the presence of the using-declaration,
which would be found by a lookup, is immaterial in determining whether
the friend declaration is a redeclaration.

--
William M. Miller, wmm@fastdial.net
Software Emancipation Technology (www.setech.com)


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: 1999/07/22
Raw View
fvali@biotrack.com writes:

> I would interpret this fragment unambiguously as well-formed according
> to 7.3.3 Paragraphs 1 and 3, which pretty much say that using
> declarations are tantamount to declarations in the scope in which they
> are used, even though they may be perceived as 'synonyms' for other
> declarations.

Well, paragraph 3 says that the using-declaration is a
member-declaration, not that the entities referred-to by the
using-declaration are members of the namespace.

If the functions really *where* members, then the following would be
ill-formed:

namespace A{long foo(){}}
namespace B{void foo(){}}
namespace C{
  using A::foo;
  using B::foo;
}

This "declares" two member functions into namespace C; A::foo and
B::foo. Now, according to 8.3.5, [dcl.fct]/3, this would be
ill-formed, right?

>> A single name can be used for several different functions in a
>> single scope; this is function overloading (clause 13). All
>> declarations for a function with a given parameter list shall agree
>> exactly both in the type of the value returned and in the number
>> and type of parameters; the presence or absence of the ellipsis is
>> considered part of the function type.

We have two declarations for the single name foo with no parameters;
one that returns long, and one that returns void, in the single scope
C.

However, I believe that the intention of the committee was that the
above example is well-formed. The only conclusion is that
using-declarations *do not* declare the functions in the namespace.

Therefore, "when looking for a prior declaration of a class or a
function declared as a friend" (7.3.1.2/3), the using-declaration is
not a declaration of the function. So, the friend declaration is
"first", and it therefore declares the friend in the enclosing
namespace. Then, the friend declaration (in the example of the issue)
conflicts with the using-declaration, as explained in 7.3.3/11.

Please note that many compilers will not assume that the following is
well-formed:

void foo();
namespace A{
  using ::foo;
  class X{
    int i;
  };
}

void foo(){
  A::X x;
  x.i=4;
}

Compilers (MSVC, Sun CC 5, TenDRA, egcs) will complain that i is not
accessible, which tells that they declared A::foo as a friend.

This is the issue.

Regards,
Martin
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Martin von Loewis <loewis@informatik.hu-berlin.de>
Date: 1999/07/14
Raw View
 [Moderator's note: this defect report has been forwarded to the
 C++ committee for consideration.
 (The same applies to all other messages in comp.std.c++ whose
 subject line starts with "Defect Report:", but previously I had
 been forgetting to add a moderator's note that said so.)
  -moderator (fjh).]

According to 7.3.1.2, [namespace.memdef]/3, a friend declaration
declares a new namespace member if that is the *first* declaration.
It also says that namespaces other than the enclosing are not
considered in looking for a prior declaration. This text is ambiguous
in the presence of using-declarations:

void foo();
namespace A{
  using ::foo;
  class X{
    friend void foo();
  };
};

This fragment could be interpreted as well-formed, since the friend
declaration in class X considers the enclosing namespace, finds the
using-declaration, and then declares ::foo as a friend of A::X.

Alternatively, this fragment could be interpreted as
ill-formed. Lookup in the enclosing namespace does not find a prior
declaration of foo (in that namespace), therefore, this is the first
declaration of void foo(void) in ::A. This would then be ill-formed
according to 7.3.3, [namespace.udecl]/11.

If you need further information, please let me know.

Regards,
Martin
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]