C++ 朋友模板函数 - minGW 错误但不是 VS2015
C++ friend template function - minGW error but not VS2015
以下代码在 Visual Studio 2015 中编译没有问题,但在 minGW 中会出现下面显示的警告和错误:
#include <iostream>
using std::ostream;
template<typename ElemType, int SIZE>
class Array
{
friend ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
ElemType operator[](int index) const;
private:
ElemType elements[SIZE];
};
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value)
{
out << elements[0];
return out;
}
mingw32-g++.exe -Wall -g -pedantic-errors -pedantic -Wextra -Wall -std=c++98 -c Test.cpp
Test.cpp:7:79: warning: friend declaration 'std::ostream& operator<<(std::ostream&, const Array<ElemType, SIZE>&)' declares a non-template function [-Wnon-template-friend]
Test.cpp:7:79: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Test.cpp: In function 'std::ostream& operator<<(std::ostream&, const Array<ElemType, SIZE>&)':
Test.cpp:21:11: error: 'elements' was not declared in this scope
我在这方面还不是专家,所以我不确定问题出在哪里。它似乎告诉我它需要在 class 本身的朋友声明之前的以下代码,但是当我把它放在那里时它会导致其他编译错误:
template<typename ElemType, int SIZE>
提前致谢!
按照@Trevor Hickey 在他的 post 下方建议的更改后,有关朋友模板功能的警告消失了。但是,我仍然收到有关 "elements" (在友元函数中)未在范围内声明的错误。
您正在使用 class 中的模板参数,但该函数本身不是模板函数。它需要是定义中所见的模板函数。
#include <iostream>
using std::ostream;
template<typename ElemType, int SIZE>
class Array
{
template<typename T, int U>
friend ostream &operator<<(ostream &out, const Array<T, U> &value);
ElemType operator[](int index) const;
private:
ElemType elements[SIZE];
};
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value)
{
out << value.elements[0];
return out;
}
您的代码中存在两个不同的问题。比较简单的是out << elements[0];
应该是out << value.elements[0];
。这是因为您要打印属于参数 value
的元素。请记住,我们在这里是一个非成员函数,没有 this
,也没有可以通过非限定名称访问的成员。
另一个被称为 template friends problem。到目前为止你只得到一个警告,但是如果你试图编译一个完整的程序你会得到一个错误。我添加了代码:
int main() { Array<int, 5> a; std::cout << a; }
出现错误:
undefined reference to `std::ostream& operator<< <int, 5>(std::ostream&, Array<int, 5> const&)'
问题是你的代码:
friend ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
实际上声明了一个非模板 函数,它将成为Array
这个实例的友元。稍后,当您在 main
中写入 cout << a
时,编译器会将 <<
匹配到此非模板声明。它永远不会达到您稍后提供的 operator<<
的正文,因此永远不会实例化该正文的副本,因此出现未定义的引用错误。
解决此问题的一种方法是显式实例化主体。但这是蹩脚的,因为您必须为您的代码发生的每个可能的 Array
实例化编写一个显式实例化。所以我们不会这样做。
最简单的解决方案是将 operator<<
的主体内联到 class 定义中。
另一种选择是声明operator<<
是一个模板函数。
Trevor Hickey 的代码展示了一种这样做的方法,尽管它有一个缺点,即 Array<A, B>::elements
可以被 Array<C, D>::operator<<
访问。
更安全的方法是在 class:
之前声明 operator<<
template<typename ElemType, int SIZE>
class Array;
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
然后是你之前的代码的其余部分。现在,class 中的 friend
声明将匹配预先存在的模板,而不是声明新的非模板。
以下代码在 Visual Studio 2015 中编译没有问题,但在 minGW 中会出现下面显示的警告和错误:
#include <iostream>
using std::ostream;
template<typename ElemType, int SIZE>
class Array
{
friend ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
ElemType operator[](int index) const;
private:
ElemType elements[SIZE];
};
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value)
{
out << elements[0];
return out;
}
mingw32-g++.exe -Wall -g -pedantic-errors -pedantic -Wextra -Wall -std=c++98 -c Test.cpp
Test.cpp:7:79: warning: friend declaration 'std::ostream& operator<<(std::ostream&, const Array<ElemType, SIZE>&)' declares a non-template function [-Wnon-template-friend]
Test.cpp:7:79: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Test.cpp: In function 'std::ostream& operator<<(std::ostream&, const Array<ElemType, SIZE>&)':
Test.cpp:21:11: error: 'elements' was not declared in this scope
我在这方面还不是专家,所以我不确定问题出在哪里。它似乎告诉我它需要在 class 本身的朋友声明之前的以下代码,但是当我把它放在那里时它会导致其他编译错误:
template<typename ElemType, int SIZE>
提前致谢!
按照@Trevor Hickey 在他的 post 下方建议的更改后,有关朋友模板功能的警告消失了。但是,我仍然收到有关 "elements" (在友元函数中)未在范围内声明的错误。
您正在使用 class 中的模板参数,但该函数本身不是模板函数。它需要是定义中所见的模板函数。
#include <iostream>
using std::ostream;
template<typename ElemType, int SIZE>
class Array
{
template<typename T, int U>
friend ostream &operator<<(ostream &out, const Array<T, U> &value);
ElemType operator[](int index) const;
private:
ElemType elements[SIZE];
};
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value)
{
out << value.elements[0];
return out;
}
您的代码中存在两个不同的问题。比较简单的是out << elements[0];
应该是out << value.elements[0];
。这是因为您要打印属于参数 value
的元素。请记住,我们在这里是一个非成员函数,没有 this
,也没有可以通过非限定名称访问的成员。
另一个被称为 template friends problem。到目前为止你只得到一个警告,但是如果你试图编译一个完整的程序你会得到一个错误。我添加了代码:
int main() { Array<int, 5> a; std::cout << a; }
出现错误:
undefined reference to `std::ostream& operator<< <int, 5>(std::ostream&, Array<int, 5> const&)'
问题是你的代码:
friend ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
实际上声明了一个非模板 函数,它将成为Array
这个实例的友元。稍后,当您在 main
中写入 cout << a
时,编译器会将 <<
匹配到此非模板声明。它永远不会达到您稍后提供的 operator<<
的正文,因此永远不会实例化该正文的副本,因此出现未定义的引用错误。
解决此问题的一种方法是显式实例化主体。但这是蹩脚的,因为您必须为您的代码发生的每个可能的 Array
实例化编写一个显式实例化。所以我们不会这样做。
最简单的解决方案是将 operator<<
的主体内联到 class 定义中。
另一种选择是声明operator<<
是一个模板函数。
Trevor Hickey 的代码展示了一种这样做的方法,尽管它有一个缺点,即 Array<A, B>::elements
可以被 Array<C, D>::operator<<
访问。
更安全的方法是在 class:
之前声明operator<<
template<typename ElemType, int SIZE>
class Array;
template<typename ElemType, int SIZE>
ostream &operator<<(ostream &out, const Array<ElemType, SIZE> &value);
然后是你之前的代码的其余部分。现在,class 中的 friend
声明将匹配预先存在的模板,而不是声明新的非模板。