我有这样的模板类,其中包含一个friend方法:
template<class T1, class T2, int n>
class Graph final
{
private:
std::array<T1, n> vertex;
std::array<std::array<T2, n>, n> arcs;
public:
Graph(const std::array<T1, n> & v, const std::array<std::array<T2, n>, n> & a);
friend std::ostream & operator<<(std::ostream & os, const Graph<T1, T2, n> & g);
};
template<class T1, class T2, int n>
Graph<T1, T2, n>::Graph(const std::array<T1, n> & v, const std::array<std::array<T2, n>, n> & a)
: vertex(v)
{ ... }
template<class T1, class T2, int n>
std::ostream & operator<<(std::ostream & os, const Graph<T1, T2, n> & g)
{ ... }
该类用于保存图形。 Vertex是一个存储节点的数组,T1是对应的元素类型。 Arcs 是一个 n * n 的二维数组,存储节点之间的路径开销,T2 是对应的元素类型。(注意,n 是模板非类型参数。)
我尝试创建一个
Graph
并调用这样的朋友方法:
void test() {
using std::array;
array<int, 5> vertex = {100, 200, 300, 400, 500};
array<int, 5> a = {2, 3, 2, 4, 5};
array<array<int, 5>, 5> arcs = {a, a, a, a, a};
Graph<int, int, 5> g(vertex, arcs);
std::cout << g << std::endl;
}
只得到错误:
tree_mst.h:31:87: warning: friend declaration ‘std::ostream& meyok::operator<<(std::ostream&, const Graph<T1, T2, n>&)’ declares a non-template function [-Wnon-template-friend]
friend std::ostream & operator<<(std::ostream & os, const Graph<T1, T2, n> & g);
^
tree_mst.h:31:87: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
../lib/libmtree.so: undefined reference to `operator<<(std::ostream&, Graph<int, int, 5ull> const&)'
../lib/libmtree.so: undefined reference to `Graph<int, int, 5ull>::Graph(std::array<int, 5ul> const&, std::array<std::array<int, 5ul>, 5ul> const&)'
为什么这里会弹出警告和错误。我该如何解决?
friend
声明为Graph
的每个实例声明一个名为operator<<
的常规非模板函数,并将此实例化作为参数。例如,您的程序使用 Graph<int, int, 5>
- 当编译器第一次看到它时,它会生成一个声明
std::ostream & operator<<(std::ostream & os, const Graph<int, int, 5>& g);
请注意,这与您的
operator<<
函数模板是分开且不同的。
然后编译器会看到
std::cout << g
并执行重载决策来为 operator<<
选择最佳重载。由于非模板函数优于函数模板,因此在其他条件相同的情况下,选择由 friend
声明引入的函数。最后,链接器发现这个函数从未被实际实现过;因此出现错误。
最有可能的是,您的意思是与
operator<<
模板参数匹配的 Graph
函数模板的特化应该是该 Graph
特化的友元。你这样表达:
// Forward declaration
template<class T1, class T2, int n>
class Graph;
// Forward declaration
template<class T1, class T2, int n>
std::ostream & operator<<(std::ostream & os, const Graph<T1, T2, n> & g);
template<class T1, class T2, int n>
class Graph
{
public:
friend std::ostream & operator<< <T1, T2, n>(std::ostream & os, const Graph<T1, T2, n> & g);
};
但是,完全避免
friend
并将 operator<<
委托给成员函数通常更简单:
template<class T1, class T2, int n>
class Graph
{
public:
void print(std::ostream& os) const { /* actual output logic here */);
};
template<class T1, class T2, int n>
std::ostream& operator<<(std::ostream& os, const Graph<T1, T2, n>& g) {
g.print(os);
return os;
}