c++重载输入输出函数时怎么解决 “[Warning] declares a non-template function”?

我在做一道c++模板题,描述如下:
“为Array类创建一个模板。这个模板允许在编译的时候Array对象实例化指定元素个数的特定的元素类型。”
而当我重载输入输出流函数的时候编译总是不通过。

编译器显示:
[Warning] friend declaration 'std::istream& operator>>(std::istream&, Array<T, n>&)' declares a non-template function [-Wnon-template-friend]
[Warning] friend declaration 'std::ostream& operator<<(std::ostream&, const Array<T, n>&)' declares a non-template function [-Wnon-template-friend]

代码如下:

#include<iostream>
using namespace std;
template<class T,int n>
class Array
{
    private:
        T p[n];
        static int count;
    public:
        friend istream & operator>> (istream & in, Array<T,n>& a);
        friend ostream & operator << (ostream & out,const Array<T,n>& a);
        int getSize()
        {
            return n;
        }
        static int getArrayCount()
        {
            return count;
        }
};
template<class T,int n>
istream & operator >> (istream & in,const Array<T,n>& a)
{
    for(int i=0;i<n;i++)
    {
        in>>a.p[i];
    }
    a.count++;
    return in;
}
template<class T,int n>
ostream & operator << (ostream & out,const Array<T,n>& a)
{
    for(int i=0;i<n;i++)
    {
        out<<a.p[i]<<" ";
    }
    return out;
}

在此贴上主函数:

int main()
{
    Array< int, 5 > intArray1;
    cin >> intArray1;
    Array< int, 5 > intArray2;
    cin >> intArray2;
    Array< float, 5 > floatArray;
    cin >> floatArray;
    cout << "\nIntArray1 contains " << intArray1.getSize() << " Elements.\n";
    cout << "The values in intArray are:\n";
    cout << intArray1;
    cout << "\nIntArray2 contains " << intArray2.getSize() << " Elements.\n";
    cout << "The values in intArray are:\n";
    cout << intArray2;
    cout << "\nDoubleArray contains " << floatArray.getSize() << " Elements.\n";
    cout << "The values in the doubleArray are:\n";
    cout << floatArray;
    cout << "\nThere are " << Array<int,5>::getArrayCount() << " Array<int,5> objects.\n";
    cout << "\nThere are " << Array<float,5>::getArrayCount() << " Array<float,5> objects.\n";
    return 0;
}

我在网上查了很久,也尝试了很多解决方法,可是无论是在
istream & operator >> (istream & in,const Array<T,n>& a)
这一行里的 >> 后面加上 <> 还是把输入输出函数在类里面定义,都是不行。
如果在类里面定义的话,就会显示如下错误:
undefined reference to `Array<float, 5>::count'
[Error] ld returned 1 exit status

如果在 >> 后面加上 <> 的话,会显示如下错误:
[Error] template-id 'operator>><>' in declaration of primary template

所以现在举步维艰,完全没有头绪。
还望各路大神能解答我的疑惑并解释一下为什么会出现以上三种错误。
万分感谢!

阅读 6.9k
2 个回答

首先静态成员变量count需要在类外定义。

其次,问题主要出在试图将函数模板的某个特化声明为类的友元,标准貌似不支持这个(具体的wording没有找到)。同样的效果可以通过简单的在类模板内定义函数友元来实现:

template <class T>
class X {
  friend void foo(T) { /* ... */ }
};

或将函数模板声明为类模板的友元:

template <class T>
class X {
  template <class U>
  friend void foo(U);
};

@felix 老大已经完全解答了OP你的问题, 窝稍微做点微不足道的补充:

  1. 将其声明为类模板的友元会破坏类的封装性, 比如X<int>的友元函数foo此时会对所有X<T>可见. 那么就等于X<int>间接不合理的获取了所有X<T>的信息(比如其private member). 所以不建议使用, 比如下段代码可以过编译.
#include<iostream>
using namespace std;
template<typename T>
class A
{
private:
    T x;
    void setter(T y)
    {
        x = y;
    }
public:
    explicit A(T a) : x(a) {}
    template<typename U>
    friend void foo(A<U> a);
};
A<int> x(7);
template<typename U>
void foo(A<U> a)
{
    x.x = 2;
}
int main()
{
    A<int> a(7);
    A<float> b(1.1);
    foo(b);
}
  1. 还有第三种方式, 是使用前置声明的方法, 详见下面代码.
  2. 首先静态成员变量count需要在类外定义从c++1z开始可能需要改成首先non-constexpr的静态成员变量count需要在类外定义。详见http://eel.is/c++draft/depr.s... . demo可以在写个odr-use函数试出.
  3. 题主你的const出问题了.
#include<iostream>
using namespace std;

template<class T, int n>
class Array;

template<class T, int n>
 istream & operator>> (istream & in, Array<T,n>& a);


template<class T,int n>
ostream & operator << (ostream & out,const Array<T,n>& a);

template<class T, int n>
class Array
{
private:
    T p[n];
    static int count;
public:
    friend istream & operator>> <> (istream & in, Array<T,n>& a);
    friend ostream & operator << <> (ostream & out,const Array<T,n>& a);
    int getSize()
    {
        return n;
    }
    static int getArrayCount()
    {
        return count;
    }
};
template<class T,int n>
istream & operator >> (istream & in, Array<T,n>& a)
{
    for(int i=0;i<n;i++)
    {
        in>>a.p[i];
    }
    a.count++;
    return in;
}
template<class T,int n>
ostream & operator << (ostream & out,const Array<T,n>& a)
{
    for(int i=0;i<n;i++)
    {
        out<<a.p[i]<<" ";
    }
    return out;
}

template<class T, int n>
int Array<T, n>::count = 0;


int main()
{
    Array< int, 5 > intArray1;
    cin >> intArray1;
    Array< int, 5 > intArray2;
    cin >> intArray2;
    Array< float, 5 > floatArray;
    cin >> floatArray;
    cout << "\nIntArray1 contains " << intArray1.getSize() << " Elements.\n";
    cout << "The values in intArray are:\n";
    cout << intArray1;
    cout << "\nIntArray2 contains " << intArray2.getSize() << " Elements.\n";
    cout << "The values in intArray are:\n";
    cout << intArray2;
    cout << "\nDoubleArray contains " << floatArray.getSize() << " Elements.\n";
    cout << "The values in the doubleArray are:\n";
    cout << floatArray;
    cout << "\nThere are " << Array<int,5>::getArrayCount() << " Array<int,5> objects.\n";
    cout << "\nThere are " << Array<float,5>::getArrayCount() << " Array<float,5> objects.\n";
    return 0;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏