簡體   English   中英

最煩人的朋友? 使用專門的自由函數模板會引發編譯錯誤(當重載方法時)

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

我將問題簡化為此示例(粘貼為單個塊以便於編譯)

/// \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;
}

細節

基本上,我試過的編譯器(VS 2010和G ++ 4.7.2)給我一個錯誤

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

他們似乎認為我聲明了一個名為overloadedMethod的數據成員。

如果出現以下情況,則不會引發編譯錯誤

  • 我將自由功能模板的非專業版作為好友(注釋的代碼行)
  • 我從類AbstractA中刪除了成員函數overloadedMethod()

問題

我無法解釋這種語言的行為,所以我的問題是:

  • 什么是導致此錯誤的C ++規則? (為什么編譯器會認為我在這里聲明了一個數據成員?)
  • 你知道背后的理由嗎? (我特別好奇,如果我從類AbstractA中刪除了overloadedMethod() ,它似乎有效。或者它是一個UB?)

首先,你friend宣言的基本前提是合理的:

[C++11: 14.5.4/1]:類或類模板的朋友可以是函數模板或類模板,函數模板或類模板的特化,或普通(非模板)函數或類。 對於不是模板聲明的友元函數聲明:

  • 如果朋友的名字是限定或不合格的模板ID ,則友元聲明引用功能模板的特化 ,否則
  • 如果friend的名稱是qualified-id並且在指定的類或命名空間中找到匹配的非模板函數,則friend聲明引用該函數,否則,
  • 如果friend的名稱是qualified-id並且在指定的類或命名空間中找到匹配的函數模板,則friend聲明引用該函數模板的推導特化(14.8.2.6),否則,
  • 名稱應為聲明(或重新聲明)普通(非模板)函數的非限定id

[例如:

 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; }; 

[..] - 最后的例子]

您可能遇到問題,因為基類中的名稱overloadedMethod 隱藏了全局問題 - 無論參數列表如何不同,以及基本名稱不代表模板這一事實:

[C++11: 3.4.1/9]:在授予友誼的類中內聯定義的友元函數(11.3)定義中使用的名稱的名稱查找應按照成員函數定義中的查找進行。 如果在授予友誼的類中未定義友元函數,則友元函數定義中的名稱查找應如命名空間成員函數定義中的查找所述進行。

[C++11: 3.4.1/10]: 在命名成員函數的friend聲明中,首先在范圍內查找函數聲明符中使用的名稱而不是declarator-id中的template-argument的一部分。成員函數的類 (10.2)。 如果找不到,或者名稱是declarator-id中 template-argument的一部分,則查找與授予友誼的類定義中的非限定名稱一樣。

在這種情況下,永遠不會觸發“if not found”子句。

在GCC 4.8.1中, 這導致以下診斷

錯誤:字段'overloadedMethod'具有不完整的類型

我確信這個診斷的具體內容有點錯誤 - 通過將template-parameter-list <A>應用於它認為不是模板的東西,你基本上混淆了你的編譯器。

即使通過限定friend聲明 ,你也無法解決這個問題:

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

以下工作:

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

但我認為這實際上是一個基於上述規則的編譯器錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM