专门化模板类的朋友(c++)

friend of specialized template class (C++)

本文关键字:c++ 朋友 专门化      更新时间:2023-10-16
#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;
}

我想为test类创建一个朋友类(在实际情况中,它是一个运算符<<)ofstream)。但是我不知道如何定义专门化类的模板友元函数。

此外,上面的代码显示了编译错误消息;

错误C2248: 'test::y':不能访问声明的私有成员类的测试"

添加问题;

Aaron McDaid对我来说很好,但是我试图重载operator<<ofstream类的。

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)我不明白为什么会发生这种情况。错误信息是

错误C2027:使用未定义类型'std::basic_ofstream<_element,_Traits>'

这个好友不是模板,而是一个普通的函数:

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类的朋友,但这往往不是一个大问题

(更新:这是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<<作为模板。此外,我在声明操作符的地方定义了操作符,并将其声明为友元。老实说,我认为还有其他更好的方法,但这对我来说很有效。

试试这个,它可以工作

#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模板类的一个参数。如果你想让它们都有相同的模板参数,那么IMO你需要显式地声明

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

函数aint (template<> int a(int& x))的专门化在这里也没有用。你需要有

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