在 gcc 和 msvc 中与特定专业化交好,但在 clang 中不起作用

Befriending specific specialization works in gcc and msvc but not in clang

提问人:Alan 提问时间:11/12/2023 最后编辑:Davis HerringAlan 更新时间:11/12/2023 访问量:100

问:

我想让一个专业成为朋友,如下所示。我用 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); 
}

演示

我有两个问题:

  1. 有没有办法让这个专业化成为朋友,以便所有编译器都接受该程序?也就是说,我想要一种解决方法,使这个特定的专业化成为朋友而不是所有人。void fun2<T>(typename Ext<T>::Inner&);Ext

  2. 上面显示的程序(在我的帖子中)在 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); 
C++ 语言-律师 C++20 模板专精会 士朋友

评论

0赞 Red.Wave 11/12/2023
我猜你的意思是 ,而不是 ;两者的含义截然不同。所以,我建议你编辑。此外,如果这是最小的可重现样本,最好也包含诊断消息。最后一点,您是否尝试过将上述定义放在上面,或者至少为模板提供正向声明?instantiationspecializationfun2Extfun2
1赞 Weijun Zhou 11/12/2023
@Red.Wave是不可能的,因为它有一个类型的参数。Ext<T>::Inner
1赞 HolyBlackCat 11/12/2023
@Red.Wave,我认为OP用的词是正确的。“专业化”有两个含义:显式/部分化,或替换了特定参数的模板化实体。“实例化”是从模板生成专用化的过程。
2赞 HolyBlackCat 11/12/2023
@Red.Wave 是 的专业化。他们并没有将朋友声明本身称为一个,而是指一种专业化。fun2<T>fun2
1赞 Weijun Zhou 11/12/2023
OP确实在标题中使用了错误的短语“明确的专业化”,但现在这个问题已经得到修复,“专业化”一词本身在这种情况下是正确的。

答:

1赞 user12002570 11/12/2023 #1

似乎该程序格式不正确,gcc 和 msvc 在接受该程序时是错误的。

第一个说明是指函数模板的专用化。来自 temp.friendfun2<T>

  1. 类或类模板的友元可以是函数模板或类模板、函数模板或类模板的专用化,也可以是非模板函数或类。 对于不是模板声明的友元函数声明

    1.1) 如果好友的名称是限定或非限定的 template-id,则好友声明是指函数模板的专用化,否则,

    1.2)

    1.3)

    1.4)


接下来,从 temp.deduct.decl 开始:

  1. 在声明者 id 引用函数模板专用化的声明中,执行模板参数推导以标识声明所引用的专用化。具体而言,这是针对显式实例化、显式专用化和某些友元声明完成的。这样做也是为了确定释放函数模板专用化是否与放置运算符 new ([basic.stc.dynamic.deallocation], [expr.new]) 匹配。 在所有这些情况下,P 是被视为潜在匹配的函数模板的类型,A 是声明中的函数类型,或者是与放置运算符 new 匹配的释放函数的类型,如 [expr.new] 中所述。 扣减按照 [temp.deduct.type] 中的描述进行。

  2. 如果对于这样考虑的函数模板集,在考虑部分排序 ([temp.func.order]) 后没有匹配项或多个匹配项,则推导失败,并且在声明情况下,程序格式不正确。

(强调我的)

在我们的示例中,集合是空的,因此没有匹配项,这意味着根据上面引用的引用,程序格式不正确。