Document number: |
00-0040/N1263 |
Date: |
September 5, 2000 |
Author: |
John Spicer, Edison Design Group |
|
jhs@edg.com |
Default Arguments and Friend Declarations (issue #136)
Introduction
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 C {
friend void f(T, T=0, T); // #2
};
C 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:
-
Permit default arguments on friend declarations provided the friend declaration
is the only declaration of the function.
-
Prohibit default arguments in friend declarations.
-
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 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
-
this issue shows default arguments in friend declarations to
be problematic
-
a simple prohibition is better than a more complicated rule
I disagree with this rationale:
-
Default arguments in friend declarations are not at all problematic
if restricted as proposed in #1.
-
I don't believe that we should remove a feature from the language
without strong justification, and such justification does not exist
in this case. Friend definitions with default arguments (as illustrated
above) work as expected in a variety of compilers (all of the compilers
that I tried).
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:
If a friend declaration specifies a default argument expression, that
declaration must be the only declaration of the function or function template
in the program.
End of document.