Topic: When exactly are injected friend declarations visible?


Author: David Krauss <potswa@gmail.com>
Date: Thu, 30 Sep 2010 01:56:05 CST
Raw View
On Sep 19, 10:56 am, sold <so...@ymail.com> wrote:
> Thanks for the responses.
>
> > Some part of the Standard says that such a declaration does not add names to
> > any scope
>
> I think the section you refer to is 14.6.5/2. It says as a comment
> that "Friend declarations do not introduce new names into any scope,
> either when the template is declared or when it is instantiated" ("the
> template" is a class template in which they're declared). The wording
> does seem contradictory to the rest of the section.
> Btw, this section also refers to 3.4.2, simply as "the rules for
> associated classes", which is both shorter and more explicit than
> 7.3.1.2, in my opinion.
>
> > The rationale makes sense, but if the user wants it to be found, they
> > can simply add a declaration at namespace scope.
>
> They can't, if the class is a class template, and the firend's
> signature depends on it's template parameters (sort of Barton-
> Nackman).
> They can declare a more-templated function at namespace scope, but,
> although similiar, it's not excatly the same.

That is true, but in such a case it will usually depend on the host
class anyway, so ADL will still find it. There are certainly
exceptions to this rule, but are there any that come from a good
design?

Looking at the various references in other quotes above, I don't see
anything that says the friend's name is introduced into the lexical
scope of the class it's in. Only that note that a friend declaration
doesn't add any name to any scope. So, that would imply that *even
inside the class block* the friend is still being found only by ADL.
Meaning an inline, non-dependent friend declaration has absolutely no
effect unless redeclared in the namespace.

The template system is there for a reason. C++ just isn't designed for
metaprogramming a factory for non-template overloads. For one thing,
that would allow querying whether a template has been instantiated
*anywhere*, by checking for the existence of a friend. That is simply
not a solvable problem, unless you decide that the friend functions
are declared and defined at the point of the implicit instantiation.
Such an ugly policy wouldn't mesh with existing semantics.

Hmmm, maybe I should try to put my money where my mouth is and code up
a demo. Not tonight, though.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: David Krauss <potswa@gmail.com>
Date: Fri, 1 Oct 2010 12:51:07 CST
Raw View
On Sep 30, 2:56 am, David Krauss <pot...@gmail.com> wrote:

> That is true, but in such a case it will usually depend on the host
> class anyway, so ADL will still find it. There are certainly
> exceptions to this rule, but are there any that come from a good
> design?

Well, I shouldn't say that. The classic example is that regular
pointers create dependency but smart pointers don't. There must be an
elegant fix to this problem, but implicit namespace declaration isn't
it. Just peeking at the result type of operator-> of the passed
argument and deciding to be dependent on the result of drill-down
(maybe only as a fallback case) would be a better, if still horribly
arbitrary, solution.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: sold <sold2@ymail.com>
Date: Sun, 19 Sep 2010 09:56:45 CST
Raw View
Thanks for the responses.

> Some part of the Standard says that such a declaration does not add names to
> any scope

I think the section you refer to is 14.6.5/2. It says as a comment
that "Friend declarations do not introduce new names into any scope,
either when the template is declared or when it is instantiated" ("the
template" is a class template in which they're declared). The wording
does seem contradictory to the rest of the section.
Btw, this section also refers to 3.4.2, simply as "the rules for
associated classes", which is both shorter and more explicit than
7.3.1.2, in my opinion.

> The rationale makes sense, but if the user wants it to be found, they
> can simply add a declaration at namespace scope.

They can't, if the class is a class template, and the firend's
signature depends on it's template parameters (sort of Barton-
Nackman).
They can declare a more-templated function at namespace scope, but,
although similiar, it's not excatly the same.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: sold <sold2@ymail.com>
Date: Tue, 14 Sep 2010 13:19:12 CST
Raw View
Hi there.

When a friend function is declared within a (non-local) class, and
isn't excplicitly declared in the enclosing namespace scope (or any of
it's enclosing namespaces for that matter), under what conditions
exactly is it visible? I find the standard to be quite ambiguous and
redundant about this. Different compilers have different takes on it
either.

Roughly speaking, compilers I've tested tend to go with one of these:

1. The function is visible as if it was explicitly declared in the
enclosing namespace, including during unqualified (non ADL) lookup,
and qualified lookup. This is obviously wrong.

2. The function is only visible during ADL, whenever the namespace
into which it was injected is among the associated namespaces.

3. The function is only visible during ADL, whenever the class in
which it was declared is among the associated classes.

(note that 1 > 2 > 3)

As it turns out, some compilers place additional semantics. GCC, for
instance, goes with option 3 for non-template friend functions, but
for friend function templates it goes with 1. I am not sure whether
it's a bug or whether it's intentional, since there could be some
rational behind it (namely, if the function requires explicit template
arguments it couldn't be found through ADL, and therefore couldn't be
found at all otherwise), but I didn't notice the standard making any
distinction between template and non-template friends (in this
context).

The standard says on 7.3.1.2/3: "... the friend class or function is a
member of the innermost enclosing namespace. The name of the friend is
not found by simple name lookup ... 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". Which implies option 2.

On 3.4.2/3: "Any namespace-scope friend functions declared in
associated classes are visible within their respective namespaces even
if they are not visible during an ordinary lookup". Which implies
option 3.

To sum it up... Which is right, if any? What are the complete,
unambiguous terms under which the injected name is visible?

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Johannes Schaub (litb)" <schaub-johannes@web.de>
Date: Wed, 15 Sep 2010 12:14:41 CST
Raw View
sold wrote:

> Hi there.
>
> When a friend function is declared within a (non-local) class, and
> isn't excplicitly declared in the enclosing namespace scope (or any of
> it's enclosing namespaces for that matter), under what conditions
> exactly is it visible? I find the standard to be quite ambiguous and
> redundant about this. Different compilers have different takes on it
> either.
>

Some part of the Standard says that such a declaration does not add names to
any scope (I can't remember whether it's a note or not). But I think that's
not correct because they do always add a name into their namespace, see the
note in 3.3/4 why this is needed. That name is not visible normally, though,
but only to ADL.

> Roughly speaking, compilers I've tested tend to go with one of these:
>
> 1. The function is visible as if it was explicitly declared in the
> enclosing namespace, including during unqualified (non ADL) lookup,
> and qualified lookup. This is obviously wrong.
>

This is wrong, yes.

> 2. The function is only visible during ADL, whenever the namespace
> into which it was injected is among the associated namespaces.
>

This is too wide.

> 3. The function is only visible during ADL, whenever the class in
> which it was declared is among the associated classes.
>

This is it, i think. Your question is about unqualified-ids, but there is
something related to this here for friend functions that use qualified-ids:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#143 for the fix
for the wording.


> (note that 1 > 2 > 3)
>
> As it turns out, some compilers place additional semantics. GCC, for
> instance, goes with option 3 for non-template friend functions, but
> for friend function templates it goes with 1. I am not sure whether
> it's a bug or whether it's intentional, since there could be some
> rational behind it (namely, if the function requires explicit template
> arguments it couldn't be found through ADL, and therefore couldn't be
> found at all otherwise), but I didn't notice the standard making any
> distinction between template and non-template friends (in this
> context).
>

The Standard explicitly covers this case where explicit arguments are needed
by an example - see 14.8.1/6.

> The standard says on 7.3.1.2/3: "... the friend class or function is a
> member of the innermost enclosing namespace. The name of the friend is
> not found by simple name lookup ... 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". Which implies option 2.
>

This is just a short and quick summary of ADL and links to 3.4.2 ...

> On 3.4.2/3: "Any namespace-scope friend functions declared in
> associated classes are visible within their respective namespaces even
> if they are not visible during an ordinary lookup". Which implies
> option 3.
>

.. Which defines its behavior.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: David Krauss <potswa@gmail.com>
Date: Wed, 15 Sep 2010 12:13:32 CST
Raw View
On Sep 14, 2:19=A0pm, sold <so...@ymail.com> wrote:

> As it turns out, some compilers place additional semantics. GCC, for
> instance, goes with option 3 for non-template friend functions, but
> for friend function templates it goes with 1. I am not sure whether
> it's a bug or whether it's intentional, since there could be some
> rational behind it (namely, if the function requires explicit template
> arguments it couldn't be found through ADL, and therefore couldn't be
> found at all otherwise), but I didn't notice the standard making any
> distinction between template and non-template friends (in this
> context).

Indeed. I tried on GCC 4.5.2 and it's still like that. Looks like a
bug.

The rationale makes sense, but if the user wants it to be found, they
can simply add a declaration at namespace scope. Usually when GCC
purposely modifies standard behavior, there's a DR behind it.

> The standard says on 7.3.1.2/3: "... the friend class or function is a
> member of the innermost enclosing namespace. The name of the friend is
> not found by simple name lookup ... 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". Which implies option 2.

The phrase "... the name lookup that considers functions..." doesn't
define a process, it merely refers to ADL. I think the "that" is a key
word. You clipped off the "(3.4.2)" at the end; it's referencing the
other paragraph you quoted.

The 7.3.1.2/3 can easily be read as a recap of what ADL does, however
redundant.

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]