哪一个编译器是对的?
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;
}
编译好: gcc版本4.8.5(Ubuntu 4.8.5-2ubuntu1~14.04.1)
导致错误: clang版本3.4-1ubuntu3(标签/ RELEASE_34 / final)(基于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.
答案 0 :(得分:2)
§11
8默认参数(8.3.6)中的名称在声明点绑定,并在此处检查访问 指向而不是默认参数的任何使用点。访问检查中的默认参数 功能模板和类模板的成员函数按照14.7.1。
中的描述执行
§14.7.1
12如果以需要使用默认参数的方式调用函数模板
f
,则依赖名称 查找,检查语义约束,以及默认情况下使用的任何模板的实例化 参数完成就像默认参数是函数模板特化中使用的初始化器一样 具有相同的范围,相同的模板参数和与功能模板f
相同的访问权限 在那时使用。此分析称为默认参数实例化。实例化的默认参数 然后用作f
的参数。
所以,根据这个,我猜想gcc的解释是对的。 fun
可以访问私有成员,因此应该在同一访问中考虑其默认参数。但我正在阅读14.7.1(12)适用于成员模板的行,而不仅仅是函数模板。我也可能误解了14.7.1(12)的意思。
答案 1 :(得分:0)
我在msvc13中测试了代码。此代码有效:
class A
{
template <typename T>
static void funPrivate() {}
public:
template <typename T>
void fun(void (*f)() = funPrivate<T>) {}
};