【发布时间】:2010-12-19 17:13:57
【问题描述】:
我正在努力解决this question 中描述的问题(将模板函数声明为模板类的朋友),我相信第二个答案是我想要做的(转发声明模板函数,然后命名专业化为朋友)。我有一个问题,一个稍微不同的解决方案实际上是正确的还是恰好在 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> 访问。我通过在operator<< 中实例化test<int> 并访问私有成员来对此进行了测试;当我尝试输出 test<double> 时,这应该会导致编译错误。
概要:在上面的代码中删除前向声明并切换到替代朋友声明似乎会产生相同的结果(在 Visual C++ 2008 中)——这段代码真的正确吗?
更新:以上对代码的任何修改在 gcc 下都不起作用,所以我猜测这些是 Visual C++ 编译器中的错误或“功能”。不过,我仍会感谢熟悉该标准的人提供的见解。
【问题讨论】:
-
顺便说一句,我发现在类声明之前添加
using namespace std;将消除对前向声明的需要,我猜这是(可能的)编译器错误的副作用。 -
根据我的评论-您可以明确添加您所说的示例(包括实例化)吗?口头上很难理解您对每个示例的含义。
标签: c++ visual-c++ templates friend-function