在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是正确的?
我相信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或在类外使用
但是指定它是,因此它不再是模板类。它是否可以像虚函数一样专门化或重写?