繁体   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