【问题标题】:friend of specialized template class (C++)专门模板类 (C++) 的朋友
【发布时间】:2012-01-21 22:53:41
【问题描述】:
#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

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

错误 C2248: 'test::y' : 无法访问声明的私有成员 类'测试'

已添加问题;

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 int) 我不明白为什么会这样。错误信息是

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

【问题讨论】:

    标签: c++ templates compiler-errors friend template-specialization


    【解决方案1】:

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

    friend int a(T& x); 
    

    要拥有一个也是朋友的模板,请尝试:

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

    在 cmets 的讨论之后,也许我应该表明我打算将这些声明用于 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 类的朋友,但这通常不是什么大问题。

    【讨论】:

    • friend int a&lt;&gt;(int&amp; x);
    • @Xeo,这是不正确的。 a 的参数是 test&lt;int&gt; ,而不是 int
    • @Aaron:对,我没注意到。但是,Bo 的回答也是错误的,因为如果 test 曾经用两种不同的类型实例化,则会造成 ODR 违规。
    • 我同意我的看法。我已经发布了一个答案(g++ 4.4.3)。但我仍然有兴趣了解其他(经过全面测试的)解决方案。
    • 我的friend 有什么问题?请注意,我使用了不同的模板参数U,并且没有在朋友声明中使用T。它确实使所有as 成为所有tests 的朋友,但这只是一个小小的不便。
    【解决方案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&lt;int&gt;&amp; 的参数,而不是int&amp;。因此,两条朋友线应替换为:

    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 &lt;fstream&gt;)。在我的回答中,operator &lt;&lt; 不是模板,而是一个正常的重载函数。我不确定是否可以将operator&lt;&lt; 作为模板。另外,我在声明并声明为友元的地方定义了运算符。老实说,我认为还有其他可能更好的方法,但这对我有用。

    【讨论】:

    • 你能回答我上面的附加问题吗
    【解决方案3】:

    试试这个,然后it works

    #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);
    

    对于int (template&lt;&gt; int a(int&amp; x)) 的函数a 的特化在这里也没有用。你需要有

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

    【讨论】:

    • 如果我尝试使用非专业测试,那对我来说是失败的。 ideone.com/nQCFc链接失败prog.cpp:(.text+0x92): undefined reference to int a(test&)'`
    • 我已经决定暂时不赞成或反对任何事情。事情总是一团糟!
    • .. 特别是我不明白为什么我的原版 (ideone.com/3KGU4) 有效,而我对您的修改 (ideone.com/nQCFc) 无法链接。
    • 您的template &lt;typename U&gt; int a(U&amp; x) 应该是template &lt;typename U&gt; int a(test&lt;U&gt;&amp; x),以确保非专业版本正常工作。见这里:ideone.com/EtuBD
    • @AaronMcDaid:哎呀。是的,对。我忘了。这是correct code。现在可以了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 2011-10-14
    • 2013-04-09
    • 1970-01-01
    相关资源
    最近更新 更多