(C++)专用模板类的友元函数

3
#include <iostream>
using namespace std;
template <typename T>
class test
{
    T y;

public:
    test(T k) : y(k) {}
    friend int a(T& x);
};

template <typename T>
int a(T& x)
{
    cout << x.y;
    return 9;
}

template <>
class test<int>
{
    int y;
public:
    test(int k) : y(k) {}
    friend int a(int& x);
};

template <>
int a<int>(int& x)
{
    cout << "4";
    return 0;
}

int main(int argc, char* argv[])
{
    test<int> z(3);
    a(z);

    return 0;
}

我希望能创建一个测试类的友元类(在实际情况中,它是ofstream的operator<<)。但我不知道如何定义专门类的模板友元函数。
此外,上面的代码显示了以下编译错误消息;
error C2248: 'test::y' : cannot access private member declared in class 'test'
附加问题:
Aaron McDaid 对我来说很好用,但我正在尝试重载ofstream类的operator<<。
friend ofstream& operator<< <test<int>> (ofstream& os, const test<int>& t);

我在测试类中添加了上面的代码

template<>
ofstream& operator<< <test<int> > (ofstream& os, const test<int>& t)
{
    os << t.y;
    return os;
}

我使用了上面的代码。但似乎我不能使用os << t.y(它是int)。我不明白为什么会出现这种情况。错误信息如下:

error C2027: use of undefined type 'std::basic_ofstream<_Elem,_Traits>'

3个回答

4

这个朋友不是模板,而是普通函数:

friend int a(T& x); 

要拥有一个既是模板又是朋友的模板,请尝试:
template<class U>
friend int a(U& x); 

在评论中的讨论后,也许我应该表明我打算将这些声明用于 test 类及其特化:

template <typename T>
class test
{
    T y;

public:
    test(T k) : y(k) {}

    template<class U>
    friend int a(U& x); 
};

template <>
class test<int>
{
    int y;
public:
    test(int k) : y(k) {}

    template<class U>
    friend int a(U& x); 
};

一点小缺点是这会使得所有 a 函数都成为所有 test 类的友元函数,但通常不是很大的问题。

2
或者 friend int a<>(int& x); - Xeo
@Xeo,那不正确。a的参数是test<int>,而不是int - Aaron McDaid
@Aaron:是的,我没有注意到。然而,如果test以两种不同的类型被实例化,那么Bo的答案也是错误的,因为它会产生ODR冲突。 - Xeo
我同意,我已经发布了一个答案(g++ 4.4.3)。但我仍然很想听听其他(完全测试过的)解决方案。 - Aaron McDaid
你能否修改你的回答,以明确表示两个 friend 行都应该替换为你的 template<class U> friend int a(U& x);?这样正确吗?我没有对你的回答进行投票,但我还没有准备好百分之百地点赞 :-) - Aaron McDaid
显示剩余2条评论

2
(更新:这是一个经过充分测试的版本,可以在http://ideone.com/3KGU4上找到。对于附加问题,请参见http://ideone.com/w0dLo)。
普通的重载函数和模板函数之间存在差异。例如,开发人员可以声明不涉及模板的函数:
void f(int x);
void f(char *x);

另一种选择是,开发者可以使用模板。

template <class T> void f(T x);

一个主要的区别是,使用普通函数时,您必须提前决定一组允许的参数,并且必须为每个参数提供实现。而使用模板,则可以更加灵活。
在程序的后期,很明显您想要将 a 定义为一个模板函数,而不仅仅是一个(重载的)普通函数。但是当编译器首次看到 a 的提及(大约在第10行附近),它看起来像是在声明一个普通函数。为了解决这个问题,您必须采取两个步骤。必须尽早声明 a 是一个模板函数,因此您的第一行应该是:
template <typename T> int a(T& x);

然后您必须声明相关的友元。如果Tint,那么a需要一个test<int>&参数,而不是int&。因此,这两个友元行应该被替换为:

friend int a<test<T> >( test<T> & x); // around line 10
friend int a<test<int> >( test<int> & x); // around line 27

a的专业化应该是:

template <>
int a< test<int> >(test<int>& ) // around line 30

额外问题

使用 ostream 替代 ofstream(或者如果只输出到文件而不是 cout,则包含 #include <fstream>)。在我的答案中,operator << 不是一个模板,而是一个普通的重载函数。我不确定是否可能将 operator<< 设为模板。此外,我将运算符定义在声明它的地方,并声明为友元。说实话,我认为还有其他,也许更好的方法,但这对我有效。


请问您能否回答我上面的附加问题? - Jaebum

0

试试这个,它能正常工作

#include <iostream>
using namespace std;

template <typename T>
class test;

template <typename T>
int a( test<T>& x);

template <typename T>
class test
{
    T y;

public:
    test(T k) : y(k) {}
    friend int a<T>( test<T>& x);
};

template <typename T>
int a( test<T>& x)
{
    cout << x.y;
    return 9;
}

template <>
class test<int>
{
    int y;
public:
    test(int k) : y(k) {}

    friend int a<int>( test<int> & x);
};

template <>
int a< int >( test<int> & x)
{
    cout << "4";
    return 0;
}

int main(int argc, char* argv[])
{
    test<int> z(3);
    a(z);

    return 0;
}

问题是,模板函数 a 接受一个 test 模板类的参数。如果你希望它们都具有相同的模板参数,那么我认为你需要明确地声明一下。
template <typename T>
    int a( test<T>& x);

此处也不需要为 int 专门定制函数 atemplate<> int a(int& x))。你需要有

template <> int a<int>( test<int> & x)

如果我尝试使用非专用测试,那么这对我来说是失败的。http://ideone.com/nQCFc 链接失败 prog.cpp:(.text+0x92): undefined reference to int a<long>(test<long>&)'` - Aaron McDaid
我决定暂时不会给任何东西点赞或点踩。事情一直出错! - Aaron McDaid
特别是我不明白为什么我的原始代码(http://ideone.com/3KGU4)可以运行,而我对你的修改后的代码(http://ideone.com/nQCFc)却无法链接。 - Aaron McDaid
你的 template <typename U> int a(U& x) 应该改为 template <typename U> int a(test<U>& x),以确保非特化版本能够正常工作。参见这里:http://ideone.com/EtuBD - Aaron McDaid
@AaronMcDaid:哎呀,是的,我忘了。这里是正确的代码。现在它可以工作了。 - ali_bahoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接