Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A question about name lookup with friend function

I have read the standard section of [basic.lookup.unqual] and I am confused about this:

typedef int f;
namespace N {
  struct A {
    friend void f(A &);
    operator int();
    void g(A a) {
      int i = f(a);  // f is the typedef, not the friend function: equivalent to int(a)
    }
  };
}

Please consider the above code; I don't understand why name f is type int, instead of void f(A &). In my understanding, the name lookup should find void f(A &) firstly in class scope A. If no name can be found there, it would perform a lookup in outside namespace. Obviously, there is a name void f(A &) in class A and as the standard says:

name lookup ends as soon as a declaration is found for the name

So why does the name refer to type int here, if there are other particular rules about these?

like image 956
xmh0511 Avatar asked Apr 23 '20 03:04

xmh0511


People also ask

Are friend functions member functions?

Even though the prototypes for friend functions appear in the class definition, friends are not members functions. We can declare friend functions anywhere in a class definition, that is either in public, private or protected sections.

How do you invoke a friend function in a class?

We can invoke it like any normal function of the class. Friend functions have objects as arguments. It cannot access the member names directly and has to use dot membership operator and use an object name with the member name. We can declare it either in the ‘public’ or the ‘private’ part.

How to declare a friend function in C++?

The friend function is declared using the friend keyword inside the body of the class. class className { ... .. ... friend returnType functionName (arguments); ... .. ... } By using the keyword, the ‘friend’ compiler understands that the given function is a friend function.

What is the purpose of using the default VLOOKUP names?

Vlookup names fix the range so that the user does not get any error while executing the Vlookup function for any type of range. Do not consider the header while naming the selected range.


1 Answers

Firstly, the friend declaration itself doesn't make f visible for name lookup, f could only be found by ADL.

A name first declared in a friend declaration within class or class template X becomes a member of the innermost enclosing namespace of X, but is not visible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided

From the standard, [namespace.memdef]/3,

The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup. [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). — end note ] If a friend function or function template 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 ([basic.lookup.argdep]). If the name in a friend declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.

The problem is for ADL to be applied, whether f(a) is a function call must be determined in advance.

[basic.lookup.unqual]/3,

(emphasis mine)

The lookup for an unqualified name used as the postfix-expression of a function call is described in [basic.lookup.argdep]. [ Note: For purposes of determining (during parsing) whether an expression is a postfix-expression for a function call, the usual name lookup rules apply.

In this stage, the function name f is invisible and the typename f is found, then f(a) is considered not to be a function all, then ADL won't be applied at all.

Because the expression is not a function call, the argument-dependent name lookup ([basic.lookup.argdep]) does not apply and the friend function f is not found.

BTW: Adding the declaration of f at namespace scope makes the function name f visible and f(a) would be considered as function call (and then you'll get the error that f returns void which can't be used to initialize i). e.g.

typedef int f;
namespace N {
  struct A;
  void f(A &);
  struct A {
    friend void f(A &);
    operator int();
    void g(A a) {
      int i = f(a);  // f is the friend function now
    }
  };
}
like image 79
songyuanyao Avatar answered Oct 09 '22 07:10

songyuanyao