我一直在努力解决这个问题中描述的问题(将模板函数声明为模板类的朋友),我相信第二个答案是我想要做的(转发声明模板函数,然后将专业化命名为朋友)。我有一个问题,一个稍微不同的解决方案实际上是正确的还是恰好在 Visual C++ 2008 中工作。
测试代码为:
#include <iostream>
// forward declarations
template <typename T>
class test;
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t);
template <typename T>
class test {
friend std::ostream& operator<< <T>(std::ostream &out, const test<T> &t);
// alternative friend declaration
// template <typename U>
// friend std::ostream& operator<<(std::ostream &out, const test<T> &t);
// rest of class
};
template <typename T>
std::ostream& operator<<(std::ostream &out, const test<T> &t) {
// output function defined here
}
首先,我发现的一件奇怪的事情是,如果我更改了 的前向声明operator<<
使其不匹配(例如,std::ostream& operator<<(std::ostream &out, int fake);
,一切仍然编译并正常工作(要清楚,我不需要定义这样的函数,只声明它)。但是,与链接到的问题一样,删除前向声明会导致问题,因为编译器似乎认为我声明的是数据成员而不是友元函数。我很确定这种行为是一个 Visual C++ 2008 错误。
有趣的是,当我在上面的代码中删除前向声明并使用替代朋友声明时。请注意,模板参数U
不会出现在以下签名中。此方法也可以正确编译和工作(无需更改任何其他内容)。我的问题是这是否符合标准或 Visual C++ 2008 的特性(我在参考书中找不到好的答案)。
请注意,虽然朋友声明template <typename U> friend ... const test<U> &t);
也有效,但这实际上使运算符的每个实例都friend
可以访问 的任何实例test
,而我想要的是test<T>
只能从operator<< <T>
. test<int>
我通过在内部实例化operator<<
并访问私有成员来测试这一点;当我尝试输出test<double>
.
概要:在上面的代码中删除前向声明并切换到替代朋友声明似乎会产生相同的结果(在 Visual C++ 2008 中)——这段代码真的正确吗?
更新:上述对代码的任何修改在 gcc 下都不起作用,所以我猜这些是 Visual C++ 编译器中的错误或“功能”。我仍然希望熟悉该标准的人提供见解。