当前位置: 首页 > 知识库问答 >
问题:

可能的gcc错误,而成为模板专门化的朋友

殷轶
2023-03-14

在SO上回答另一个问题时,我遇到了一个有点可疑的gcc编译器错误。令人不快的片段是

template <class T> class A;
template <class T, class U>
void operator*(A<T>, A<U>);

template <class T>
class A {
    friend void ::operator*(A<T>, A<T>);
...

谁的最后一行给出了著名的警告

好友声明'空运算符*(A

导致稍后出现硬错误。完整的代码可以在这里找到。

现在,问题是我认为这种行为是不合适的。[temp.friend]/1 中的标准说:

对于不是模板声明的友元函数声明:

—如果友元的名称是限定或非限定的template-id,则友元声明引用函数模板的专门化,否则

-如果友元的名称是限定id,并且在指定的类或命名空间中找到匹配的非模板函数,则友元声明引用该函数,否则,

-如果友元的名称是限定id,并且在指定的类或命名空间中找到模板函数的匹配专门化,则友元声明引用该函数专门化,否则,

这是C 03;C 11 包含类似的子句

模板的特殊化由[temp.spec]/4定义:

…专门化是实例化或显式专门化的类、函数或类成员(14.7.3)。

和[temp.fct.spec]/1:

从函数模板实例化的函数称为函数模板特化;所以是函数模板的显式特化。可以显式指定模板参数...

[temp.arg.explicit]/2说明了如何为函数规范指定模板参数列表:

当引用函数模板的专门化时,可以指定模板参数列表

...

-在朋友声明中。

可以推导的尾随模板参数(14.8.2)可以从显式模板参数列表中省略。如果所有的模板参数都可以被推导出来,那么它们都可以被省略;在这种情况下,空模板参数列表

因此,通过[temp.fct.spec]/1,< code>::operator*

我认为强调的条件已经满足;因此,友元声明应该使类与运算符模板(隐式)专门化成为友元。然而,gcc却不这么认为,并继续使用第四个项目符号,该项目符号仅涉及由非限定id指定的朋友,尽管该朋友实际上是由限定id命名的。

在这种情况下,我的解释是正确的还是gcc是正确的?


共有1个答案

何灼光
2023-03-14

我相信gcc是正确的。

首先是目前的措辞:

如果友元的名称是限定id,并且在指定的类或命名空间中找到了匹配的函数模板,则友元声明引用该函数模板的推断专门化(14.8.2.6),否则

根据[14.8.2.6从函数声明推导模板参数]:

1 在声明器-id 引用函数模板的特化的声明中,将执行模板参数推导以标识声明所引用的特化。具体来说,这是针对显式实例化 (14.7.2)、显式专用化 (14.7.3) 和某些友元声明 (14.5.4) 完成的。这样做也是为了确定解除分配函数模板专用化是否与放置运算符 new 匹配(3.7.4.2、5.3.4)。在所有这些情况下,P 是被视为潜在匹配项的函数模板的类型,而 A 是声明中的函数类型,或者是与放置运算符 new 匹配的解除分配函数的类型,如 5.3.4 中所述。扣除按照14.8.2.5中所述完成。

2 如果对于如此考虑的函数模板集,在考虑了偏序 (14.5.6.2) 后没有匹配项或有多个匹配项,则演绎失败,并且在声明情况下,程序格式不正确。

在您的情况下,不会执行模板参数推导,因为声明符-id不引用专业化。我认为重要的部分是,它的声明符-id引用专业化作为发生这种情况的条件。简而言之,您需要

更新:让我们分析一下这种情况下的声明器id:

qualified-id:
nested-name-specifier templateopt unqualified-id
:: identifier
:: operator-function-id
:: literal-operator-id
:: template-id

从上面的语法可以看出,< code>void ::operator*(A

 类似资料:
  • 还尝试在专门化的中进行模板方法专门化: 这一次它编译,但调用原始方法,即 解决方案

  • 考虑以下头文件和源文件: 我在

  • ii)当我更改代码并删除void_t时 0和0打印。表示,专门化是,所以我们使用基本模板。对于字符串,专门化无论如何都失败了。 我的问题:iii)有趣的部分。如果现在我把第一行改为使用int作为默认类型 有人能给我解释一下在iii)发生了什么吗?

  • 以下构建设置在使用GCC(4.6.3)的Linux上运行良好,但在使用GCC(4.7.2)的MinGW上则不然。 在 Linux 上,我们有: 这正是我所期待的。在Windows上,我们有 我怀疑这和弱符号有关。也就是说,Linux我们在foo. o有 而且在baro 而在Windows上,我们在foo.o中有这样的功能 而且在baro 因此,没有弱符号可以覆盖。 解决这个问题的最好方法是什么?在

  • 我有以下模板方法: 但是我得到了那些奇怪的链接错误: /usr/lib/gcc/x86_64-redhat-linux/4.4。7/../../../../包括/c/4.4。7/例外:62:void MyStruct::readField(std::basic_istream)的多重定义 如何专门化此成员函数? 编辑 这种方法在以下方面起作用: 或者使用s或在类外使用

  • 但是指定它是,因此它不再是模板类。它是否可以像虚函数一样专门化或重写?