Which one of the compilers is right ?
class A
{
public:
template <typename T>
void fun(void (*f)() = funPrivate<T>) {}
private:
template <typename T>
static void funPrivate() {}
};
int main(int argc, char** argv)
{
A a;
a.fun<int>();
return 0;
}
Compiles fine on: gcc version 4.8.5 (Ubuntu 4.8.5-2ubuntu1~14.04.1)
Results in a error on: clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
a.cpp:5:27: error: 'funPrivate' is a private member of 'A'
void fun(void (*f)() = funPrivate<T>) {}
^~~~~~~~~~~~~
a.cpp:14:3: note: in instantiation of default function argument expression for 'fun<int>' required here
a.fun<int>();
^
a.cpp:8:16: note: declared private here
static void funPrivate() {}
^
1 error generated.
§ 11
8 The names in a default argument (8.3.6) are bound at the point of declaration, and access is checked at that
point rather than at any points of use of the default argument. Access checking for default arguments in
function templates and in member functions of class templates is performed as described in 14.7.1.
§ 14.7.1
12 If a function template f
is called in a way that requires a default argument to be used, the dependent names
are looked up, the semantics constraints are checked, and the instantiation of any template used in the default
argument is done as if the default argument had been an initializer used in a function template specialization
with the same scope, the same template parameters and the same access as that of the function template f
used at that point. This analysis is called default argument instantiation. The instantiated default argument
is then used as the argument of f
.
So, according to this, I would guess that gcc's interpretation is right. fun
has access to private members, so its default arguments should be considered in that same access. But I am reading between the lines that 14.7.1(12) applies to member templates, and not just function templates. Also I may be misunderstanding that 14.7.1(12) means.
I have tested code in msvc13. This code works:
class A
{
template <typename T>
static void funPrivate() {}
public:
template <typename T>
void fun(void (*f)() = funPrivate<T>) {}
};