我试图了解模板和友元在 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 ,我们需要前向声明。那是为了
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 只会在我们使用/调用它时占用空间(内存)。这是正确的结论吗?我的 第三个问题是我有 read那:
There is no way to explicitly specify template arguments to overloaded operators, conversion functions, and constructors, because they are called without the use of the function name.
根据上面引用的语句,我们不能为重载运算符显式指定模板参数,但是如何写
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 。原因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<>
的情况下这是不可能的因为该函数不接受任何依赖于模板参数的参数。
关于c++ - C++ 中的类模板和友元,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69000196/