我想将单一专业作为朋友,如下所示。我用 C++20 尝试了以下操作,但该程序被 clang 拒绝,并被 GCC 和 MSVC 接受。
template <class T>
struct Ext {
struct Inner
{
int m{};
};
/*Is there a way to make this specialization work with all the compilers?
Note that I know that I can write template<typename S> friend void fun2(Ext<T>::Inner&)
but I only want to make this specialization a friend
*/
friend void fun2<T>(typename Ext<T>::Inner&); //C++20: works in gcc and msvc but rejected by clang
};
template <class T>
void fun2(typename Ext<T>::Inner &p)
{
p.m = 10;
}
int main()
{
Ext<int>::Inner x;
fun2<int>(x);
}
我有两个问题:
有没有办法让这个专业化
void fun2<T>(typename Ext<T>::Inner&);
成为朋友,以便该程序被所有编译器接受?也就是说,我想要一种解决方法,使这个特定的专业化成为朋友而不是所有Ext
。
上面显示的程序(在我的帖子中)在 C++20 中格式正确吗?
叮 说:
<source>:13:16: error: no candidate function template was found for dependent friend function template specialization
13 | friend void fun2<T>(typename Ext<T>::Inner&); //C++20: works in gcc and msvc but rejected by clang
| ^
<source>:24:15: error: use of undeclared identifier 'x'
24 | fun2<int>(x);
看来程序是格式错误并且gcc和msvc在接受程序时是错误的。
首先注意,
fun2<T>
指的是函数模板的特化。来自temp.friend:
类或类模板的友元可以是函数模板或类模板,函数模板或类模板的特化,或者非模板函数或类。 对于不是模板声明的友元函数声明:
1.1) 如果友元的名称是限定或非限定的 template-id,则友元声明指的是函数模板的特化,否则,
1.2)
1.3)
1.4)
接下来,来自 temp.deduct.decl:
在其 declarator-id 引用函数模板的特化的声明中,将执行模板参数推导来识别该声明所引用的特化。 具体来说,这是为了显式实例化、显式专业化和某些友元声明而完成的。 这样做还可以确定解除分配函数模板特化是否与放置运算符 new ([basic.stc.dynamic.deallocation], [expr.new]) 匹配。 在所有这些情况下,P 是被视为潜在匹配的函数模板的类型,A 是声明中的函数类型或与放置运算符 new 匹配的释放函数的类型,如 [expr.new 中所述]。 扣除按照 [temp.deduct.type] 中的描述进行。
如果对于如此考虑的一组函数模板,在考虑部分排序([temp.func.order])后没有匹配或有多个匹配,则推导失败,并且在声明情况下,程序格式错误。
(强调我的)
在我们的示例中,该集合是空的,因此没有匹配项,这意味着根据上面引用的参考,该程序的格式不正确。