[英]Friend function with a definition - template or non-template?
假設我們有以下代碼:
template<class T> struct S;
template<class T> void operator++(S<T>);
template<class T> struct S {
friend void operator++(S);
};
template<class T>
void operator++(S<T>) {}
int main() {
S<int> s;
++s;
}
這將編譯但不會鏈接,因為friend
聲明引入了一個從未定義過的非模板operator++
。
這個常見問題解答的內容如下(粗體是我的):
解決方案是在編譯器檢查 class 主體時說服編譯器,
operator++
function 本身就是一個模板。 做這件事有很多種方法;
第一種方法是在朋友聲明中加入<>
,這里不考慮。 第二個是“在class體內定義朋友function”:
template<class T> struct S {
friend void operator++(S) { }
};
引用表明void operator++(S)
現在是 function 模板,而不是非模板 function。 是嗎?
它不是模板,因為它的聲明不是模板的聲明(即使它出現在模板聲明本身中)。
[temp.friend] (強調我的)
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 a non-template function or class. 對於不是模板聲明的朋友 function 聲明:
如果朋友的名字是合格或不合格的模板ID,朋友聲明指的是function模板的特化,否則,
如果朋友的名字是qualified-id並且在指定的class或命名空間中找到匹配的非模板function,則朋友聲明指的是function,否則
如果朋友的名字是一個qualified-id並且匹配的function模板在指定的class或命名空間中找到,朋友聲明是指推導出的那個ZC1C425268E68385D1AB5074C17A9模板的特化,否則[decFlZA4]
該名稱應為聲明(或重新聲明)非模板 function 的非限定 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; };
這里,任務 class 模板的每個特化都有 function
next_time
作為好友; 因為process
沒有明確的模板參數,任務 class 模板的每個特化都有一個適當類型的 functionprocess
作為朋友,而這個朋友不是 ZC1C425268E68385D1AB5074C17A94F 因為朋友preempt
有一個明確的模板參數T
,task
class 模板的每個特化都有 function 模板作為朋友preempt
的適當特化; 並且task
class 模板的每個特化具有func
模板的所有特化作為朋友。 類似地,task
class 模板的每個特化具有 class 模板特化task<int>
作為好友,並且具有 class 模板frd
的所有特化作為好友。 —結束示例]
雖然示例是非規范性的,但引文中的示例闡明了前述規范性文本的意圖。 由於友元運算符聲明不是模板聲明,因此適用粗體文本。 因此它聲明了一個非模板 function。
和
template<class T> struct S {
friend void operator++(S s) { }
};
operator ++
不再是模板。
對於更常規的 function ( operator
用法與函數略有不同),它可能允許扣除:
template<class T> struct S {
S(T t);
friend void foo(S lhs, S rhs) { }
};
template <typename T>
void bar(S<T> s, T t)
{
foo(s, t); // would not work if foo was template, would require foo<T>(s, t);
foo(s, {t}); // would not work if foo was template, would require foo<T>(s, {t});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.