默认模板实参成员访问异常:是否属于Clang的编译BUG?
问题背景
我们来看两个C++模板相关示例:
示例1
struct A{ template<class T, int R> friend void show(); private: int c; }; template<class T, int R = decltype(T{}.c){0} > void show(){ } int main(){ show<A>(); }
示例2
struct A{ template<class T, int R> friend void show(); private: int c; }; template<class T, int R = decltype(A{}.c){0} > void show(){ } int main(){ show<A>(); }
Clang编译表现
Clang接受示例2但拒绝示例1,报错信息如下:
<source>:14:3: error: no matching function for call to 'show' show<A>(); ^~~~~~~ <source>:10:6: note: candidate template ignored: substitution failure [with T = A, R = 0]: 'c' is a private member of 'A' void show(){ ^ 1 error generated. ASM generation compiler returned: 1 <source>:14:3: error: no matching function for call to 'show' show<A>(); ^~~~~~~ <source>:10:6: note: candidate template ignored: substitution failure [with T = A, R = 0]: 'c' is a private member of 'A' void show(){ ^
结论与分析
你观察到的Clang对示例1的拒绝属于编译器Bug,不存在额外的C++标准规则支持这种差异处理,具体依据如下:
你引用的标准条款完全适用:
默认模板实参的访问权限在其声明所在上下文检查,而非在任何使用点检查。
所有访问控制规则影响从特定实体声明中命名类成员的权限,包括待声明实体名称之前的声明部分;如果实体是类,还包括出现在类成员说明之外的类成员定义。
两个示例的唯一差异是默认模板实参中访问c的对象类型是否依赖模板参数:
- 示例2的默认实参直接使用
A{}.c,Clang在show的声明上下文正确识别了show是A的友元,允许访问私有成员c,符合标准要求。 - 示例1的默认实参使用依赖模板参数的
T{}.c,Clang错误地将访问权限检查推迟到了模板实例化的使用点(也就是main函数中调用show<A>()的上下文),而main函数没有A的私有成员访问权限,因此抛出了错误,这违背了标准中默认模板实参访问权限仅在声明上下文检查的规定。
友元的访问权限覆盖整个函数声明的所有部分,包括模板参数列表、默认实参,和函数是否为模板、实参是否依赖模板参数无关。目前GCC、MSVC均能正确接受这两个示例,仅Clang存在该实现缺陷。
内容的提问来源于stack exchange,提问作者xmh0511
相关产品推荐
相关产品推荐

