简体   繁体   English

最烦人的朋友? 使用专门的自由函数模板会引发编译错误(当重载方法时)

[英]Most Vexing Friend ? Friend-ing a specialized free-function template raises compilation error (when overloading a method)

Code

I reduced the problem to this example (pasted as a single block for ease of compilation) 我将问题简化为此示例(粘贴为单个块以便于编译)

/// \brief The free-function template,
/// which is overloading a method with the same name in AbstractA below.
template <class T>
inline const T overloadedMethod(const T& lhs, const T& rhs)
{
    return T(lhs.value+rhs.value);
}

/// \brief AbstractA class
class AbstractA
{
public:
    AbstractA (int aVal):
      value(aVal)
      {}


      inline const AbstractA overloadedMethod(const AbstractA &rhs) const
      {
          return AbstractA(value+rhs.value);            
      }

protected:
    int value;
};

/// \brief A class, deriving from AbstractA,
/// and friending the free-function template.
class A : public AbstractA
{   
    friend const A overloadedMethod <A>(const A& lhs, const A& rhs);
        /// This one gives me compilation error
    //template<class T> friend const T overloadedMethod(const T& lhs, const T& rhs);
        /// This one would be okay

public:
    A (int aVal):
      AbstractA(aVal)
      {}
};

int main()
{
   A a1(1), a2(2);
   overloadedMethod(a1, a2);

   return 0;
}

Details 细节

Basically, the compilers I tried (VS 2010 and G++ 4.7.2) give me an error on the line 基本上,我试过的编译器(VS 2010和G ++ 4.7.2)给我一个错误

friend const A overloadedMethod <A>(const A& lhs, const A& rhs);

They seem to think I am declaring a data member named overloadedMethod . 他们似乎认为我声明了一个名为overloadedMethod的数据成员。

The compilation error is not raised if : 如果出现以下情况,则不会引发编译错误

  • I give the non-specialized version of the free-function template as a friend (commented line of code) 我将自由功能模板的非专业版作为好友(注释的代码行)
  • I remove the member function overloadedMethod() from class AbstractA 我从类AbstractA中删除了成员函数overloadedMethod()

Questions 问题

I am not able to explain this behavior of the langage, so my questions would be : 我无法解释这种语言的行为,所以我的问题是:

  • What is the C++ rule that is leading to this error ? 什么是导致此错误的C ++规则? (Why would compilers think I am declaring a data member here ?) (为什么编译器会认为我在这里声明了一个数据成员?)
  • Do you know a rationale behind it ? 你知道背后的理由吗? (I am especially curious to know why it seems to be working if I remove the overloadedMethod() from class AbstractA . Or is it an UB ?) (我特别好奇,如果我从类AbstractA中删除了overloadedMethod() ,它似乎有效。或者它是一个UB?)

First of all, the basic premise of your friend declaration is sound: 首先,你friend宣言的基本前提是合理的:

[C++11: 14.5.4/1]: A friend of a class or class template can be a function template or class template, a specialization of a function template or class template, or an ordinary (non-template) function or class. [C++11: 14.5.4/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 non-template function is found in the specified class or namespace, the friend declaration refers to that function, otherwise, 如果friend的名称是qualified-id并且在指定的类或命名空间中找到匹配的非模板函数,则friend声明引用该函数,否则,
  • 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),否则,
  • the name shall be an unqualified-id that declares (or redeclares) an ordinary (non-template) function. 名称应为声明(或重新声明)普通(非模板)函数的非限定id

[ Example: [例如:

 template<class T> class task; template<class T> task<T>* preempt(task<T>*); template<class T> class task { friend void next_time(); friend void process(task<T>*); friend task<T>* preempt<T>(task<T>*); template<class C> friend int func(C); friend class task<int>; template<class P> friend class frd; }; 

[..] —end example ] [..] - 最后的例子]

You can run into problems because the name overloadedMethod from the base class hides the global one — irrespective of the different argument list, and the fact that the base name does not represent a template: 您可能遇到问题,因为基类中的名称overloadedMethod 隐藏了全局问题 - 无论参数列表如何不同,以及基本名称不代表模板这一事实:

[C++11: 3.4.1/9]: Name lookup for a name used in the definition of a friend function (11.3) defined inline in the class granting friendship shall proceed as described for lookup in member function definitions. [C++11: 3.4.1/9]:在授予友谊的类中内联定义的友元函数(11.3)定义中使用的名称的名称查找应按照成员函数定义中的查找进行。 If the friend function is not defined in the class granting friendship, name lookup in the friend function definition shall proceed as described for lookup in namespace member function definitions. 如果在授予友谊的类中未定义友元函数,则友元函数定义中的名称查找应如命名空间成员函数定义中的查找所述进行。

[C++11: 3.4.1/10]: In a friend declaration naming a member function, a name used in the function declarator and not part of a template-argument in the declarator-id is first looked up in the scope of the member function's class (10.2). [C++11: 3.4.1/10]: 在命名成员函数的friend声明中,首先在范围内查找函数声明符中使用的名称而不是declarator-id中的template-argument的一部分。成员函数的类 (10.2)。 If it is not found, or if the name is part of a template-argument in the declarator-id , the look up is as described for unqualified names in the definition of the class granting friendship. 如果找不到,或者名称是declarator-id中 template-argument的一部分,则查找与授予友谊的类定义中的非限定名称一样。

The "if it is not found" clause can never be triggered in this case. 在这种情况下,永远不会触发“if not found”子句。

In GCC 4.8.1 this results in the following diagnostic : 在GCC 4.8.1中, 这导致以下诊断

error: field 'overloadedMethod' has incomplete type 错误:字段'overloadedMethod'具有不完整的类型

I'm sure that the specific contents of this diagnostic are slightly erroneous — you've basically confused the heck out of your compiler, by applying the template-parameter-list <A> to something that it does not believe is a template. 我确信这个诊断的具体内容有点错误 - 通过将template-parameter-list <A>应用于它认为不是模板的东西,你基本上混淆了你的编译器。

You cannot fix this, even by qualifying the friend declaration : 即使通过限定friend声明 ,你也无法解决这个问题:

friend const A ::overloadedMethod<A>(const A& lhs, const A& rhs);

The following does work: 以下工作:

friend auto ::overloadedMethod<A>(const A&, const A&) -> const A;

But I think that this is actually a compiler bug, based on the above rules. 但我认为这实际上是一个基于上述规则的编译器错误。

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

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