簡體   English   中英

C++ 中的類模板和友誼

[英]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>();
      |                      ^

我的第一個問題是,即使我已經評論了func4operator<<模板函數的前向聲明,那么我怎么能只得到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.

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