简体   繁体   English

在与模板专业化交朋友时可能存在gcc错误

[英]Possible gcc bug while befriending template specialization

While answering to a different question on SO, I came across a somewhat suspicious compiler error with gcc. 在回答关于SO的不同问题时,我遇到了一个与gcc有点可疑的编译器错误。 The offending snippet is 有问题的片段是

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>);
...

whose last line gives the famous warning 最后一行给出了着名的警告

friend declaration ' void operator*(A<T>, A<T>) ' declares a non-template function friend声明' void operator*(A<T>, A<T>) '声明一个非模板函数

leading to hard errors later. 导致以后的硬错误。 The full code can be found here . 完整的代码可以在这里找到。

Now, the problem is I don't think the behavior is appropriate. 现在,问题是我不认为这种行为是恰当的。 The standard in [temp.friend]/1 says: [temp.friend] / 1中的标准说:

For a friend function declaration that is not a template declaration: 对于不是模板声明的友元函数声明:

— if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function template, otherwise - 如果朋友的名称是限定或不合格的模板ID,则友元声明引用功能模板的特化,否则

— if the name of the friend is a qualified-id and a matching nontemplate function is found in the specified class or namespace, the friend declaration refers to that function, otherwise, - 如果friend的名称是qualified-id并且在指定的类或命名空间中找到匹配的nontemplate函数,则friend声明引用该函数,否则,

— if the name of the friend is a qualified-id and a matching specialization of a template function is found in the specified class or namespace, the friend declaration refers to that function specialization, otherwise, - 如果friend的名称是qualified-id并且在指定的类或命名空间中找到了模板函数的匹配特化 ,则friend声明引用该函数的特化,否则,

this is C++03; 这是C ++ 03; C++11 contains similar clause C ++ 11包含类似的子句


A specialization of a template is defined by [temp.spec]/4: 模板的特化由[temp.spec] / 4定义:

... A specialization is a class, function, or class member that is either instantiated or explicitly specialized (14.7.3). ...专门化是实例化或显式专用的类,函数或类成员(14.7.3)。

and [temp.fct.spec]/1: 和[temp.fct.spec] / 1:

A function instantiated from a function template is called a function template specialization; 从函数模板实例化的函数称为函数模板特化; so is an explicit specialization of a function template. 所以是函数模板的显式特化。 Template arguments can either be explicitly specified ... 模板参数可以明确指定...

[temp.arg.explicit]/2 says this about specifying a template argument list for a function specification: [temp.arg.explicit] / 2说明了为函数规范指定模板参数列表:

A template argument list may be specified when referring to a specialization of a function template 当引用函数模板的特化时,可以指定模板参数列表

... ...

— in a friend declaration. - 在朋友声明中。

Trailing template arguments that can be deduced (14.8.2) may be omitted from the list of explicit template-arguments. 可以推导出的尾随模板参数(14.8.2)可以从显式模板参数列表中省略。 If all of the template arguments can be deduced, they may all be omitted; 如果可以推导出所有模板参数,则可以省略它们; in this case, the empty template argument list <> itself may also be omitted . 在这种情况下, 也可以省略空模板参数列表<>本身

So, by [temp.fct.spec]/1, ::operator*<T,T>(A<T>, A<T>) is a function template specialization; 因此,通过[temp.fct.spec] / 1, ::operator*<T,T>(A<T>, A<T>)是一个函数模板特化; and since the template parameters can be deduced, it can be referred to as ::operator*(A<T>, A<T>) . 由于可以推导出模板参数,因此可以将其称为::operator*(A<T>, A<T>) So I conclude the qualified-id in the friend declaration denotes a function template specialization. 所以我总结了friend声明中的qualified-id表示一个函数模板特化。


I think that the emphasized condition is fulfilled; 我认为强调的条件已经实现; therefore, the friend declaration should befriend the class with the operator template (implicit) specialization. 因此,友元声明应该与运营商模板(隐式)专业化的类成为朋友。 However, gcc thinks otherwise and goes on to the fourth bullet which, only concerns friends designated by unqualified-ids, even though the friend is actually named by a qualified-id . 然而,gcc认为不然,并继续第四个子弹,只涉及由不合格的id指定的朋友即使这个朋友实际上是由一个合格的id命名

Is my interpretation correct or is gcc right in this case? 在这种情况下,我的解释是正确的还是gcc?

I believe gcc is correct. 我相信gcc是正确的。

First the current wording: 首先是当前的措辞:

if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend declaration refers to the deduced specialization of that function template (14.8.2.6), otherwise 如果friend的名称是qualified-id并且在指定的类或命名空间中找到匹配的函数模板,则friend声明引用该函数模板的推导特化 (14.8.2.6),否则

From [14.8.2.6 Deducing template arguments from a function declaration]: 从[14.8.2.6推导函数声明中的模板参数]:

1 In a declaration whose declarator-id refers to a specialization of a function template, template argument deduction is performed to identify the specialization to which the declaration refers. 1 在声明中声明id引用函数模板特化的声明中,执行模板参数推导以标识声明所引用的特化。 Specifically, this is done for explicit instantiations (14.7.2), explicit specializations (14.7.3), and certain friend declarations (14.5.4). 具体来说,这是为了显式实例化(14.7.2),显式特化(14.7.3)和某些朋友声明 (14.5.4)。 This is also done to determine whether a deallocation function template specialization matches a placement operator new (3.7.4.2, 5.3.4). 这样做也是为了确定解除分配函数模板特化是否与放置运算符new匹配(3.7.4.2,5.3.4)。 In all these cases, P is the type of the function template being considered as a potential match and A is either the function type from the declaration or the type of the deallocation function that would match the placement operator new as described in 5.3.4. 在所有这些情况下,P是被认为是潜在匹配的函数模板的类型,A是声明中的函数类型或者与5.3.4中描述的匹配放置运算符new的释放函数的类型。 The deduction is done as described in 14.8.2.5. 扣除按照14.8.2.5中的描述完成。

2 If, for the set of function templates so considered, there is either no match or more than one match after partial ordering has been considered (14.5.6.2), deduction fails and, in the declaration cases, the program is ill-formed. 2如果对于所考虑的功能模板集合,在考虑部分排序后(14.5.6.2)没有匹配或多于一个匹配,则扣除失败,并且在声明情况下,程序格式错误。

In your case, template argument deduction is not performed because the declarator-id does not refer to a specialization. 在您的情况下, 执行模板参数推导,因为declarator-id不引用特化。 I think the important part is whose declarator-id refers to a specialization as the condition for this to happen. 我认为重要的部分是whose declarator-id refers to a specialization作为发生这种情况的条件。 Simply put, you need the <> for the first sentence in 14.8.2.6p1 to happen (if I am reading this correctly). 简单地说,你需要14.8.2.6p1第一句话的<> (如果我正确地读这个)。

UPDATE Let's break down what a declarator-id is for this situation: 更新让我们分解声明者id对于这种情况:

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

As seen from the above grammar, void ::operator*(A<T>, A<T>) is a :: operator-function-id and not a :: template-id . 从上面的语法可以看出, void ::operator*(A<T>, A<T>):: operator-function-id不是 :: template-id What this means is the syntax can never declare a template function (as mentioned in the error message). 这意味着语法永远不能声明模板函数(如错误消息中所述)。 For it to be a template-id you have to use operator-function-id < template-argument-listopt> syntax. 要使它成为模板ID,您必须使用operator-function-id < template-argument-listopt>语法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM