ADL fails for friend functions...

Discussion in 'C++' started by Werner, Nov 2, 2011.

  1. Werner

    Werner Guest

    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
     
    Werner, Nov 2, 2011
    #1
    1. Advertising

  2. Werner

    Edek Guest

    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
     
    Edek, Nov 2, 2011
    #2
    1. Advertising

  3. Werner

    Werner Guest

    On Nov 2, 3:40 pm, Edek <> 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
     
    Werner, Nov 2, 2011
    #3
  4. Werner

    Edek Guest

    On 11/02/2011 03:28 PM, Werner wrote:
    > On Nov 2, 3:40 pm, Edek<> 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
     
    Edek, Nov 2, 2011
    #4
  5. 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
     
    Victor Bazarov, Nov 2, 2011
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Question about ADL

    , Apr 29, 2004, in forum: C++
    Replies:
    5
    Views:
    362
    Dave Moore
    Apr 29, 2004
  2. Fraser Ross

    using declaration and ADL

    Fraser Ross, Sep 9, 2005, in forum: C++
    Replies:
    5
    Views:
    264
    Victor Bazarov
    Sep 9, 2005
  3. Chris Johnson
    Replies:
    6
    Views:
    352
    Chris Johnson
    Jul 3, 2006
  4. cgv
    Replies:
    2
    Views:
    382
    =?ISO-8859-15?Q?Jens_M=FCller?=
    Oct 14, 2006
  5. Steven T. Hatton

    What would C++ look like without ADL?

    Steven T. Hatton, Dec 14, 2006, in forum: C++
    Replies:
    7
    Views:
    310
    F.J.K.
    Dec 14, 2006
Loading...

Share This Page