[英]Class Templates and Friendship in C++
我試圖了解模板和友誼在 C++ 中是如何工作的。 所以自己尋找/嘗試一些例子。 下面給出了一個我無法理解的示例:
版本 1
#include <iostream>
using namespace std;
//template<typename T> void func4();
//template<typename T> class NAME;
// template<typename T> std::ostream& operator<< (std::ostream&, NAME<T> const&);
template<typename T>
class NAME {
friend void func4<T>();
friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
};
int main()
{
cout << "Hello World" << endl;
return 0;
}
上面的版本1給出了以下錯誤:
prog.cc:13:17: error: variable or field 'func4' declared void
13 | friend void func4<T>();
| ^~~~~
prog.cc:13:17: error: expected ';' at end of member declaration
13 | friend void func4<T>();
| ^~~~~
| ;
prog.cc:13:22: error: expected unqualified-id before '<' token
13 | friend void func4<T>();
| ^
我的第一個問題是,即使我已經評論了func4
和operator<<
模板函數的前向聲明,那么我怎么能只得到func4
錯誤? 這就是為什么operator<<
沒有錯誤的原因。
請注意,我知道如果我們想與模板的特定實例成為朋友,我們需要前向聲明。 那是為了
friend void func4<T>();
為了工作,我們需要注釋掉聲明
template<typename T> void func4();
同樣對於
friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
為了工作,我們需要在程序開始時注釋掉相應的前向聲明。 但是當我只注釋掉template<typename T> void func4();
語句,程序運行,並且operator<<
沒有錯誤。 同樣為什么我們沒有收到operator<<
的錯誤,即使我沒有注釋掉相應的前向聲明。
我的第二個問題是聲明
friend void func4<T>();
與...一樣
friend void func4<>();
同樣,是語句
friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
與...一樣
friend std::ostream& operator<< <> (std::ostream&, NAME<T> const&);
我的想法是語句friend void func4<>();
是使用語句模板聲明的函數模板的特template <typename T> void func4();
. 同時,當我們寫friend void func4<T>();
我們明確地傳遞T
所以在這種情況下,當我們編寫/調用func4<int>();
函數模板func4<int>
將被初始化,然后占用內存。 另一方面,專用模板函數已經占用了一些內存,因為我們必須在調用它之前提供它的定義。 那么有人可以解釋一下我們使用<T>
和使用<>
時是否有區別。 總之,在我看來,在<>
的情況下,將使用用戶提供的專業化,而在<T>
的情況下,當我們調用 func4() 時,將創建一個新的意圖。 所以有區別,因為在<>
情況下,我們必須提供一個已經占用一些空間(內存)的定義,而在<T>
的情況下,func4 只會在我們使用/調用它時占用空間(內存)。 這是正確的結論嗎?
我的第三個問題是我已經讀過:
無法為重載運算符、轉換函數和構造函數顯式指定模板參數,因為它們的調用不使用函數名稱。
根據上面引用的語句,我們不能為重載運算符顯式指定模板參數,但是如何編寫friend std::ostream& operator<< <T> (std::ostream&, NAME<T> const&);
因為它重載 operator << 。
答案 1 operator<<
沒有錯誤,因為您使用了using namespace std;
並且在std
命名空間中已經有重載的operator<<
。
答案 3引用的語句談到調用(即,使用)重載運算符而不是定義/聲明它們
答案 2
版本 1
#include <iostream>
template<typename T> void func4();
template<typename T>
class NAME {
//friend void func4<>();//this does not work because there is no way to deduce the template arguments
friend void func4<T>();//this works because here we have explicitly passed T as the template argument
};
int main()
{
std::cout << "Hello World" << std::endl;
NAME<int> n;
return 0;
}
在版本 1 中,我們有一個模板函數 func4<>。 現在當你寫friend void func<T>();
和friend void func<>();
,您正在成為類模板 NAME<> 的完全專業化朋友。 原因friend void func<>();
不起作用的原因是在這種情況下模板參數推導無法工作。 而當你寫friend void func<T>();
你已經明確地傳遞了模板參數,所以這是有效的。 這也意味着( friend void func<T>
和friend void func<>();
)本質上是模板函數func<> 的相同特化。 這將從我的下一個示例版本 2 中更加清楚。
版本 2
#include <iostream>
template<typename T> class NAME;
template<typename T> std::ostream& operator<<(std::ostream&, const NAME<T>& );
template<typename T>
class NAME {
//both of the below friend declarations are equivalent
friend std::ostream& operator<< <T>(std::ostream&, const NAME<T>&);//this works
friend std::ostream& operator<< <>(std::ostream&, const NAME<T>&);//this works as well becasue of template argument deduction
};
int main()
{
std::cout << "Hello World" << std::endl;
NAME<int> n;
return 0;
}
在版本 2 中,我們有一個重載的運算符模板函數。 兩個friend std::ostream& operator<< <T>(std::ostream&, const NAME<T>&);
和friend std::ostream& operator<< <>(std::ostream&, const NAME<T>&);
是等價的,並且是重載模板operator<< <T>
。 它們之間的唯一區別是第二個使用模板參數推導。 這是可能的,因為與版本 1 不同,這次我們有一個依賴於T
的函數參數,因此模板參數推導可以工作。 這在函數模板func4<>
情況下是不可能的,因為該函數不接受任何依賴於模板參數的參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.