Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > ADL fails for friend functions...

Reply
Thread Tools

ADL fails for friend functions...

 
 
Werner
Guest
Posts: n/a
 
      11-02-2011
Hi All,

Here follows a minimal example that fails to compile:

namespace n1{
class X1
{
friend void join( X1&, X1& ){ }
};

}
class Y
{
void join(){}
void foo()
{
struct{ void operator()( n1::X1&, n1::X1& ){ } }join_x;
n1::X1 xa, xb;
join( xa, xb );
}
};

The friend function join is not found because ADL is
"negated" by the Y::join.

Is there any other way to call join defined in X from within foo?
Apart
from moving the call outside the scope of Y (see next example)?

namespace n1{
class X1
{
friend void join( X1&, X1& ){ }
};

}
class Y
{
void join(){}
friend void join_x( n1::X1&, n1::X1& );
void foo();
};

void join_x( n1::X1& xa, n1::X1& xb )
{
join( xa, xb );
}

void Y::foo()
{
n1::X1 xa, xb;
join_x( xa, xb );
}

The reason I'm asking this question is because of Andrei
Alexandrescu's
choice in Modern C++ Design to use friend functions instead of member
functions for reset (compared to boost that does the opposite). I
realize
his rationale is/was to prevent accidental calling of reset for the
contained
type...

Regards,

Werner

 
Reply With Quote
 
 
 
 
Edek
Guest
Posts: n/a
 
      11-02-2011
On 11/02/2011 02:23 PM, Werner wrote:
> Hi All,
>
> Here follows a minimal example that fails to compile:
>
> namespace n1{
> class X1
> {
> friend void join( X1&, X1& ){ }
> };


You need to bring join out to make ADL consider it

namespace n1{
class X1
{
friend void join( X1&, X1& );
};

void join (X1&, X1&) {};
}
.... and ...

>
> }
> class Y
> {
> void join(){}
> void foo()
> {
> struct{ void operator()( n1::X1&, n1::X1& ){ } }join_x;
> n1::X1 xa, xb;
> join( xa, xb );
> }
> };


class Y
{
void join(){}
void foo()
{
struct{ void operator()( n1::X1&, n1::X1& ){ } }join_x;
n1::X1 xa, xb;

using ::n1::join;
join( xa, xb );
}
};

Local scope has preference in the standard: if there is a local
symbol, other lookup methods are not attempted, unless you bring
it in with "using". (I am using non-formal language, see
the standard on "using" directive). Only then regular overload
matching kicks in.

>
> The friend function join is not found because ADL is
> "negated" by the Y::join.
>
> Is there any other way to call join defined in X from within foo?
> Apart
> from moving the call outside the scope of Y (see next example)?


The above compiles with gcc and is consistent with what I know.

> The reason I'm asking this question is because of Andrei
> Alexandrescu's
> choice in Modern C++ Design to use friend functions instead of member
> functions for reset (compared to boost that does the opposite). I
> realize
> his rationale is/was to prevent accidental calling of reset for the
> contained
> type...


Could you quote directly, I am confused with what you wrote, it does not
fit anything I can come up with.

Edek


 
Reply With Quote
 
 
 
 
Werner
Guest
Posts: n/a
 
      11-02-2011
On Nov 2, 3:40*pm, Edek <(E-Mail Removed)> wrote:

> You need to bring join out to make ADL consider it
>
> namespace n1{
> class X1
> {
> * *friend void join( X1&, X1& );
>
> };
>
> void join (X1&, X1&) {};}


Yes, I know you can define it outside the class for it to be
found in the namespace (by using), but apart from that?

> Local scope has preference in the standard: if there is a local
> symbol, other lookup methods are not attempted, unless you bring
> it in with "using". (I am using non-formal language, see
> the standard on "using" directive). Only then regular overload
> matching kicks in.


My apologies, I was wanting my first example to look like this:

namespace n1{
class X1
{
friend void join( X1&, X1& ){ }
};
}

class Y
{
void join(){}
void foo()
{
n1::X1 xa, xb;
join( xa, xb );
}
};

I've deliberately not defined the friend outside. The question
still stands - can you call join in any other way than by
removing Y's join from the overload set?

> Could you quote directly, I am confused with what you wrote, it does not
> fit anything I can come up with.


Quote Modern C++ Design Ch 7.4:

"However, experience has proven that member functions are not very
suitable for smart pointers. The reason is that the interaction
between member function calls for the smart pointer for the
pointed-to object can be extremely confusing."

I've noticed that in Loki he has, depending on compiler either
defined the friends in the class or in the namespace...

For this reason (ADL not kicking in automatically if overload
exists) I'm beginning to think that this was boosts choice for using
members instead of non-members in their smart pointers.

Kind regards,

Werner







 
Reply With Quote
 
Edek
Guest
Posts: n/a
 
      11-02-2011
On 11/02/2011 03:28 PM, Werner wrote:
> On Nov 2, 3:40 pm, Edek<(E-Mail Removed)> wrote:
>
> I've deliberately not defined the friend outside. The question
> still stands - can you call join in any other way than by
> removing Y's join from the overload set?


"Using" does not remove Y::join from overload set. It adds n1::join.

>
>> Could you quote directly, I am confused with what you wrote, it does not
>> fit anything I can come up with.

>
> Quote Modern C++ Design Ch 7.4:
>
> "However, experience has proven that member functions are not very
> suitable for smart pointers. The reason is that the interaction
> between member function calls for the smart pointer for the
> pointed-to object can be extremely confusing."


Ah, yes, I missed the simplest possible thing.

If my opinion matters at all, + has the same problem. You
"never know" if you are adding 1 to a pointer to int or
to the int-pointed-to. And if an Object has a parent Object,
you never know if it is the parent or the parent's parent.
Oh, well... I can live with that. Friend reset is imo worse,
can call a member of class where it is used by mistake,
or in a better case cause ambiguity, though VC sometimes
takes shortcuts here.

>
> I've noticed that in Loki he has, depending on compiler either
> defined the friends in the class or in the namespace...
>
> For this reason (ADL not kicking in automatically if overload
> exists) I'm beginning to think that this was boosts choice for using
> members instead of non-members in their smart pointers.


Don't know. Maybe you can dig mail archives for discussions.

For me personally, the consequence of what I wrote above is that
the programmer does have to keep track of what is a pointer and
what is not a pointer. While the -> instead of . does happen
in my case sometimes (when I change a ref to a ptr or the opposite)
I have never hit the described problem. I wonder only if
I become to hit this problem since I started using auto a lot.
Still, member seems more natural to me, I find it more readable.
Also note that reset(whatever) will match reset(T) if whatever is
convertible to T and there is no preferred alternative and
reset is not a member.

Edek

 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      11-02-2011
On 11/2/2011 10:28 AM, Werner wrote:
>[..]
> namespace n1{
> class X1
> {
> friend void join( X1&, X1& ){ }
> };
> }
> [..]
> I've deliberately not defined the friend outside. The question
> still stands - can you call join in any other way than by
> removing Y's join from the overload set?


This rule comes to mind: the name of a friend function defined in the
class definition shall *not* be inserted into the namespace scope.
Don't remember where in the Standard it is, or whether it has changed
over the years... But for some reason I seem to remember that it
exists, and think that it applies here.

V
--
I do not respond to top-posted replies, please don't ask
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
What would C++ look like without ADL? Steven T. Hatton C++ 7 12-14-2006 04:07 PM
no ADL / Koenig lookup for function calls with template parameters cgv C++ 2 10-14-2006 07:50 PM
How to resolve ADL(?) issue using std::copy and std::ostream_iterator Chris Johnson C++ 6 07-03-2006 01:55 AM
using declaration and ADL Fraser Ross C++ 5 09-09-2005 04:01 PM
Question about ADL derek@cis.strath.ac.uk C++ 5 04-29-2004 02:24 PM



Advertisments