Template default arg : Friend function cannot access private member

This is regarding a test case which involves default argument deduction/substitution. The test case can be summarized as :

template <class T, class = typename T::I>h(T){}

template <class T, class = typename T::I>j(T){}

class A
typedef int I;
friend void h(A);


int main()
A a;

gcc-4.8.1 throws error for function j, since it has been not been declared friend nor it is private to class A and hence violates access rule for

private member I(which is valid). gcc does not throw error for function h since it has been declared as friend to class A and hence can access

private member I.

Clang throws error for both the functions. Error for function j (not declared friend is valid and as expected), but it throws error even for

friend function h (error : deduction of default arg failed since I is a private member of class A). This violates the accessibility of the friend


The standard says - (At 14.8.2 pt 8)

"If a substitution results in an invalid type or expression, type deduction fails. An in valid type or expression

is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as

part of the substitution process. —end note ]"

Can someone please provide inputs as to how to check where the access rights are being checked in clang? I am using QT creator to debug clang

Any Comment on this one?

Clang is actually rejecting the friend function declaration, not the call to h.

The relevant bit from the standard is [class.access]p9:
  The names in a default template-argument have their access checked in the context in which they appear rather than at any points of use of the default template-argument.

This is the resolution to DR 401:

Note in particular this quote, which illuminates the reasoning behind the somewhat confusing standard wording:
  We decided that template parameter default arguments should have their access checked in the context where they appear without special access for the entity declared…

The context in which the template parameter default argument appears is the global context, which has no special access rights to A. So Clang is correct to reject this.

GCC is probably mistakenly checking access from the context which uses the default argument. I can’t imagine that they’re really doing the heroics necessary to check access from the context of h<A> **in order to validate the declaration which makes that access well-formed**.


Thanks John for the reply. I got your point of “context to be checked where no special access is attached”. Thanks a lot.