【问题标题】:How to define and use a friend function to a temlate class with the same template?如何定义和使用同一个模板的模板类的友元函数?
【发布时间】:2010-06-15 07:17:36
【问题描述】:

我写了以下代码:

#include <iostream>
using namespace std;

template <class T>
class AA
{
  T a;

public:
AA()
{
 a = 7;
}

friend void print(const AA<T> & z);
};

template <class T>
void print(const AA<T> & z)
{
    cout<<"Print: "<<z.a<<endl;
}

void main()
{
AA<int> a;
print<int>(a);
}

并得到以下错误:

error C2248: 'AA<T>::a' : cannot access private member declared in class 'AA<T>'
1>        with
1>        [
1>            T=int
1>        ]
1>        c:\users\narek\documents\visual studio 2008\projects\aaa\aaa\a.cpp(7) : see declaration of 'AA<T>::a'
1>        with
1>        [
1>            T=int
1>        ]
1>        c:\users\narek\documents\visual studio 2008\projects\aaa\aaa\a.cpp(30) : see reference to function template instantiation 'void print<int>(const AA<T> &)' being compiled
1>        with
1>        [
1>            T=int
1>        ]

怎么了?

附:我正在使用 Visual Studio 2008。

【问题讨论】:

    标签: c++ function templates friend


    【解决方案1】:

    问题是当你做类似的事情时

    template<class T>
    class AA {friend void print(const AA<T>&);};
    

    然后你像这样实例化AA

    AA<int> a;
    

    朋友声明将被实例化

    friend void print(const AA<int>&);
    

    这是一个非模板函数!这意味着编译器不会将朋友声明与您的print 函数匹配。

    解决方案基本上是在AA 之前声明print 并明确告诉编译器您的朋友声明正在谈论模板函数。像这样:

    #include <iostream>
    using namespace std;
    
    //forward declare AA because print needs it
    template<class T>
    class AA;
    
    //declare print before AA to make the friend declaration
    //match with this function
    template<class T>
    void print(const AA<T> & z);
    
    template <class T>
    class AA
    {
            //the <> is needed to make sure the compiler knows we're
            //dealing with a template function here
            friend void print<>(const AA<T> & z);
    
        public:
            AA() {a = 7;}
    
        private:
            T a;
    };
    
    //implement print
    template<class T>
    void print(const AA<T> & z)
    {
        cout<<"Print: "<<z.a<<endl;
    }
    
    int main()
    {
        AA<int> a;
        print(a);
    }
    

    有趣的是,如果您不在朋友声明中添加&lt;&gt;,会发生什么。您将收到链接器错误。为什么?好吧,因为编译器无法将朋友声明与你的模板print 函数匹配,它会隐式假设一个带有原型的函数

    void print(const AA<int>&);
    

    存在。由于我没有为print 的调用显式提供模板参数(这不是必需的,因为编译器应该能够推断出这一点),因此编译器会将此调用与声明为friend 的函数相匹配。这个函数没有实现,因此链接器错误。

    【讨论】:

    • 它有效。这么奇怪...!如果函数是友元函数,则意味着它不是类函数。编译器如何“认为”该函数是类的函数?还是说“课内”来表达不同的意思?
    • 原来我的解释并不完全正确。编辑了它,现在应该更清楚了:)
    • 为什么要在AA之前声明打印?我以前为我的班级创建了 frind 函数,并在 .cc 文件中实现了这些函数(在课堂之后)并且它可以工作。为什么现在炸函数应该在AA之前?我的意思是它如何“帮助”编译器?
    • 您也可以在AA 之前转发声明print 函数并在其他地方实现它。我已经编辑了我的答案以显示这一点。
    • 因为编译器需要知道你在谈论一个模板函数。您可以通过在朋友声明中添加 &lt;&gt; 来做到这一点。但是如果你这样做,编译器需要知道模板函数存在。
    【解决方案2】:

    你也可以在类定义中定义友元函数:

    #include <iostream>
    using namespace std;
    
    template <class T>
    class AA
    {
        T a;
      public:
        AA()
        {
          a = 7;
        }
    
        friend void print(const AA<T> &z)
        {
          cout<<"Print: "<<z.a<<endl;
        }
    };
    
    int main()
    {
      AA<int> a;
      print(a);
    }
    

    【讨论】:

      猜你喜欢
      • 2016-10-19
      • 2010-12-19
      • 2016-06-23
      • 1970-01-01
      • 1970-01-01
      • 2016-02-24
      • 1970-01-01
      相关资源
      最近更新 更多