friend function - c++

What does the following mean (especially the highlighted portion)? Why is the expression 'f(a)' treated as a 'cast expression'?
C++03 $3.4./3- "The lookup for an unqualified name
used as the postfix-expression of a
function call is described in 3.4.2.
[Note: for purposes of determining
(during parsing) whether an expression
is a postfix-expression for a function
call, the usual name lookup rules
apply. The rules in 3.4.2 have no
effect on the syntactic interpretation
of an expression. For example,
typedef int f;
struct A {
friend void f(A &);
operator int();
void g(A a) {
f(a);
}
};
The expression f(a) is a cast-expression equivalent to int(a). Because the expression is not a function call, the argument-dependent name lookup (3.4.2) does not apply and the friend function f is not found. ]"
Any thoughts?

It means that the parser first determines whether the expression before the parentheses is an id or a postfix-expression. In this case, it sees f, and the nearest f defined is typedef int f - therefore it concludes the expression is interpreted as int(a) and no Koenig lookup is performed.
Let's have this code (you an try it online: http://ideone.com/clone/eRKvP)
typedef int f;
namespace x {
struct A {
friend void f(A &);
//friend void f(); // # 1
operator int();
void g(A a) {
//void f(); // # 2
(void)f(a); // # 3
}
};
}
Had you declared an (unrelated) function f visible from g, it would be interpreted as a function call and Koenig lookup would find the correct overload (see line #2).
The friend declaration of f should not apply here, because
11.4/1: ... The name of a friend is not in the scope of the class,
However, what's disturbing me, is that uncommenting #1 makes the compiler (gcc in this case) call x::f(A&) too. Not sure why is that. [In Comeau Online compiler, it works as expected (eg. #1 doesn't influence line #3). The latest beta version has problems compiling this code, though.]
PS: As noted by litb, the rules in C++0x are a little different:
3.4.2/3:
Let X be the lookup set produced by
unqualified lookup (3.4.1) and let Y be
the lookup set produced by argument
dependent lookup (defined as follows).
If X contains
a declaration of a class member, or
a block-scope function declaration that is not a using-declaration, or
a declaration that is neither a function or a function template
then Y is empty. Otherwise Y is the
set of declarations found in the
namespaces associated with the
The bold item will make the compiler only consider void f() and fail for too many arguments.
It seems to have been introduced by the resolution of issue 218.

Related

ADL lookup inside a class (template) member function body

struct B {};
struct C : B {};
void f(B){} // worse match than A::f<C>
struct A {
template<class T>
void f(T v) {
f(v); // #1
}
};
int main()
{
A{}.f(C{});
}
Activating ADL lookup in line #1 is as simple as
{
using ::f;
f(v);
}
I think the rule that makes the code fail without the using directive is:
[basic.lookup.argdep]/3 Let X be the lookup set produced by unqualified lookup and let Y be
the lookup set produced by argument dependent lookup (defined as
follows). If X contains
(3.1) a declaration of a class member, or
(3.2) a block-scope function declaration that is not a using-declaration, or
(3.3) a declaration that is neither a function nor a function template
then Y is empty. [...]
So, since a call to f found by non-ADL lookup will find A::f, which is a class member, overloads found by ADL-lookup are discarded.
Which C++ rule allows to ignore the restriction in 3.1 with the using declaration, to make the above code compile?
I think I'm completely misunderstanding the context where the rule [basic.lookup.argdep]/3 must be applied, or maybe I have a bigger and hidden hole in my understanding of the name lookup process.
First paragraph on unqualified name lookup:
In all the cases listed in [basic.lookup.unqual], the scopes are
searched for a declaration in the order listed in each of the
respective categories; name lookup ends as soon as a declaration is
found for the name.
In particular,
For the members of a class X, a name used in a member function body […], following
the member's declarator-id, shall be declared in one of the
following ways:
before its use in the block in which it is used or in an enclosing
block ([stmt.block]), or
shall be a member of class X or be a member
of a base class of X ([class.member.lookup]), or ...
A local (re)declaration of a name is prioritised and shadows all extrinsic declarations.

Default function parameter value visible in template but it shouldn't (gcc)

Consider the code below:
#include <utility>
void f(int, int);
void g(int, int);
struct functor
{
template<typename... T>
void operator()(T&&... params)
{
return f(std::forward<T>(params)...);
}
};
int main()
{
functor()(1); // can use the default value here, why?!
// g(1); // error here as expected, too few arguments
}
void f(int a, int b = 42) {}
void g(int a, int b = 24) {}
This is a thin wrapper around a function call. However, inside functor::operator(), f doesn't have its default value for the second parameter known (it is visible only after main, in the definition), so the code should not compile. g++5.2 compiles it successfully though, but clang++ spits out the expected message that one expects for compilers that perform the two-phase name lookup correctly:
error: call to function 'f' that is neither visible in the
template definition nor found by argument-dependent lookup
return f(std::forward(params)...);
Is this a gcc bug or I am missing something here? I.e., is the point of instantiation after the definition of f below main()? But even in this case, it shouldn't work, as at the second phase the function can only be found via ADL, which is not the case here.
[temp.dep.candidate]:
For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules ([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup ([basic.lookup.unqual]), only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either the template definition context or the template instantiation context are found.
If the call would be ill-formed or would find a better match had the lookup within the associated namespaces
considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation
contexts, then the program has undefined behavior.
Note that ADL is not even working here, as the involved types are fundamental (their set of associated namespaces is empty).

Interesting behavior of compiler with namespaces

Assume the following code:
#include <iostream>
using namespace std;
namespace X
{
class A{};
void f(A a){}
void g(int a){}
}
int main()
{
X::A a;
f(a);
g(5);
}
When I compile the code, the following compile error occurs:
main.cpp: In function 'int main()':
main.cpp: error: 'g' was not declared in this scope
So the function f is compiled perfectly, but g isn't. How? Both of them belong to the same namespace. Does the compiler deduce that function f belongs to the X namespace from the argument of type X::A? How does compiler behave in such cases?
X::A a;
f(a);
works because of Argument-Dependent Lookup (Also known as Koenig Lookup). a is an object of class A inside namespace X, when compiler searches a match-able function f, it will look into namespace X in this case. See Argument Dependent Lookup for more information.
This works for the function call expression:
f(a);
because the namespace that X::A belongs to is included in the lookup for the function f due to argument dependent lookup(ADL), cppreference explains ADL as follows:
Argument-dependent lookup, also known as ADL, or Koenig lookup, is the
set of rules for looking up the unqualified function names in
function-call expressions, including implicit function calls to
overloaded operators. These function names are looked up in the
namespaces of their arguments in addition to the scopes and namespaces
considered by the usual unqualified name lookup.
Argument-dependent lookup makes it possible to use operators defined
in a different namespace
This is covered in the draft C++ standard section 3.4.2 Argument-dependent name lookup:
When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered
during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope
friend function or function template declarations (11.3) not otherwise visible may be found
and goes on to say:
For each argument type T in the function call, there is a set of zero or more associated namespaces and a
set of zero or more associated classes to be considered. The sets of namespaces and classes is determined
entirely by the types of the function arguments (and the namespace of any template template argument).
and includes the following bullet:
If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a
member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces
of which its associated classes are members.[...]
and further down provides a similar example to your problem:
namespace NS {
class T { };
void f(T);
void g(T, int);
}
NS::T parm;
void g(NS::T, float);
int main() {
f(parm); // OK: calls NS::f
extern void g(NS::T, float);
g(parm, 1); // OK: calls g(NS::T, float)
}
The function call expression:
g(5);
does not work because ADL does not add any namespaces for arguments that are fundamental types.
Herb Sutter covers ADL in Gotw #30 and in What's In a Class? - The Interface Principle.
When the code f(a), the compiler finds the function void f(A a){} in the namespace X because of the ADL (argument dependent lookup, also known as Koenig lookup).
A is declared in the namespace X, hence when the compiler needs to look up the definition of f, it includes possibilities from that namespace because the object a of type A is in that namespace (as declared X::A a;).
On the other hand, int is not declared in the namespace X, so the namespace X is not included in the lookup. Since no corresponding function for f is found, it fails to compile.

Unqualified name lookup applied instead of argument-dependent name lookup

Consider an example from the standard sec 3.4.1/3:
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)
}
};
}
f(a) is postfix expression. How does compiler determine that f(a) is not a function call? I'm wondering when we have no error like f previously declared of typedef int f; as in the following example:
#include <stdio.h>
typedef int foo; //error: previous declaration of ‘typedef int foo’
class B
{
public:
friend void foo(B b){ printf("3"); } //error: ‘void foo(B)’ redeclared as different kind of symbol
static const int c=42;
};
int main(){ }
(In my version of the C++11 document the example is presented in 3.4.1/3).
The 3.4.1/3 clearly states that for the purposes of parsing, in order to perform the initial determination of whether this is a postfix expression or function call, a usual name lookup is performed. "Usual" means that the lookup is performed as described in the rest of 3.4.1 and no ADL is used at that initial stage. 3.4.1/3 explicitly says that "The rules in 3.4.2 have no effect on the syntactic interpretation of an expression." (3.4.2 is ADL).
In this example, while parsing f(a) the usual lookup is used to look for name f. It finds the global typedef-name ::f and nothing else. This means that f(a) is treated as a postfix expression (a cast), not as a function call. Note, that friend declaration of function f inside A refers to function N::f, but it does not introduce a declaration of N::f into N. Since N::f function is not explicitly declared in N (it is not visible in N), the usual lookup does not see it. It only sees the global ::f, which is a typedef-name.
If you want the usual name lookup to find the function in the first example, you have to declare that function in N explicitly
typedef int f;
namespace N
{
struct A; // <- added
void f(A &); // <- added
struct A
{
friend void f(A &);
...
Now the declaration of N::f is visible in N. Now the usual name lookup will find N::f and treat that f(a) as a function call from the very beginning.
Your second example is seriously different from the first. You have no extra namespace there. Because of that the friend function declaration in B refers to the global ::foo and claims that foo is a function. But the global ::foo is already declared as a typedef-name. This contradiction is exactly what causes the error.
(Amusingly, C++03 version of the standard contained an example in 3.4.1/3, which was essentially equivalent to your second example. I.e. the example in the standard was ill-formed. This is reported as Defect #139 of the standard.)

Two-phase function template compilation: not *only* ADL is employed in the 2nd phase?

I'm wondering why the following code compiles.
#include <iostream>
template<class T>
void print(T t) {
std::cout << t;
}
namespace ns {
struct A {};
}
std::ostream& operator<<(std::ostream& out, ns::A) {
return out << "hi!";
}
int main() {
print(ns::A{});
}
I was under impression that at the instantiation point unqualified dependent names are looked-up via ADL only - which should not consider the global namespace. Am I wrong?
This is an interesting case. The workings of name lookup as you describe them is summarized here:
[temp.dep.candidate] (emphasis mine)
1 For a function call where the postfix-expression is a dependent
name, the candidate functions are found using the usual lookup rules
([basic.lookup.unqual], [basic.lookup.argdep]) except that:
For the part of the lookup using unqualified name lookup, only function declarations from the template definition context are found.
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), only function declarations found in either
the template definition context or the template instantiation context
are found.
If the call would be ill-formed or would find a better match had the
lookup within the associated namespaces considered all the function
declarations with external linkage introduced in those namespaces in
all translation units, not just considering those declarations found
in the template definition and template instantiation contexts, then
the program has undefined behavior.
The bit I highlighted is the crux of the matter. The description for "ADL only" is for function calls of the from foo(bar)! It does not mention calls that result from an overloaded operator. We know that calling overloaded operators is equivalent to calling a function, but the paragraph speaks of expressions in a specific form, that of a function call only.
If one was to change your function template into
template<class T>
void print(T t) {
return operator<< (std::cout, t);
}
where now a function is called via postfix-expression notation, then wo and behold: GCC emits an equivalent error to Clang. It implements the above paragraph reliably, just not when it comes to overloaded operator calls.
So is it a bug? I would say it is. The intent is surely that overloaded operators be found like named functions (even when called from their respective expression form). So GCC needs to be fixed. But the standard could use a minor clarification of the wording too.