提问人:Alan 提问时间:11/12/2023 最后编辑:Davis HerringAlan 更新时间:11/12/2023 访问量:100
在 gcc 和 msvc 中与特定专业化交好,但在 clang 中不起作用
Befriending specific specialization works in gcc and msvc but not in clang
问:
我想让一个专业成为朋友,如下所示。我用 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 中格式是否良好?
Clang 说道:
<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 在接受该程序时是错误的。
第一个说明是指函数模板的专用化。来自 temp.friend:fun2<T>
类或类模板的友元可以是函数模板或类模板、函数模板或类模板的专用化,也可以是非模板函数或类。 对于不是模板声明的友元函数声明:
1.1) 如果好友的名称是限定或非限定的 template-id,则好友声明是指函数模板的专用化,否则,
1.2)
1.3)
1.4)
接下来,从 temp.deduct.decl 开始:
在声明者 id 引用函数模板专用化的声明中,执行模板参数推导以标识声明所引用的专用化。具体而言,这是针对显式实例化、显式专用化和某些友元声明完成的。这样做也是为了确定释放函数模板专用化是否与放置运算符 new ([basic.stc.dynamic.deallocation], [expr.new]) 匹配。 在所有这些情况下,P 是被视为潜在匹配的函数模板的类型,A 是声明中的函数类型,或者是与放置运算符 new 匹配的释放函数的类型,如 [expr.new] 中所述。 扣减按照 [temp.deduct.type] 中的描述进行。
如果对于这样考虑的函数模板集,在考虑部分排序 ([temp.func.order]) 后没有匹配项或多个匹配项,则推导失败,并且在声明情况下,程序格式不正确。
(强调我的)
在我们的示例中,集合是空的,因此没有匹配项,这意味着根据上面引用的引用,程序格式不正确。
评论
instantiation
specialization
fun2
Ext
fun2
Ext<T>::Inner
fun2<T>
fun2