Document number:  00-0040/N1263
Date:  September 5, 2000
Author:  John Spicer, Edison Design Group

Default Arguments and Friend Declarations (issue #136)


The core working group has, so far, not been able to reach consensus on how to handle default arguments in friend declarations. The example from the issue is:

void f(int, int, int=0); // #1 class C { friend void f(int, int=0, int); // #2 }; void f(int=0, int, int); // #3

The question is whether or not the default argument from declaration #2 is visible at the point of declaration #3. If it is visible, declaration #3 is valid; otherwise it is invalid. But the more relavent example is the templatized version:

void f(int, int, int=0); // #1 template <class T> class C { friend void f(T, T=0, T); // #2 }; C<int> ci; void f(int=0, int, int); // #3 We have gone to great lengths to eliminate the side-effects of class template instantiations so that the validity of a program does not depend on whether or not a given class template required instantiation. For example, we eliminate the injection of names from friend declarations. In keeping with this philosophy, it is important that default arguments on friend declarations should not be able to change the validity of other declarations of a function, or the validity of references to the function.

Summary of the Discussion to Date

The core group came up with three possible means of resolving the issue:
  1. Permit default arguments on friend declarations provided the friend declaration is the only declaration of the function.
  2. Prohibit default arguments in friend declarations.
  3. Treat the default argument information of the friend declaration as distinct from that of any declarations of the function in namespace scope.
Of these, it was agreed that #3 should be eliminated from consideration because it would be a significant language change and would not really solve the problem when a given function was a friend of more than one class.

The rationale behind #1 is to permit the following usage:

template <class T> struct A { friend void f(A, int i = 0) { /* ... */ } };

In this example, the function is defined in the friend declaration. Because there is no other declaration of the function, there is no possibility of the friend declaration introducing a side-effect. The declaration is only visible when using argument-dependent lookup.

Note that if such usage were prohibited, there is no alternate means of achieving the same semantics.

The rationale behind #2 (to prohibit default arguments in friend declarations) is that

I disagree with this rationale:

Proposed Change

We should adopt proposal #1 above that permits default arguments in friend declarations only when the friend declaration is the only declaration of the function.

Wording Changes

In 8.3.6 [dcl.fct.default] add after paragraph 4:

End of document.