我想知道如果函数的模板参数包括但不限于类的模板参数,如何使函数成为类的朋友并在类外部定义函数。
例如,我具有以下模板类和模板好友功能:
template<int N> class Matrix;
template<typename T, int N> Matrix<N> operator*(const Matrix<N> &m1, const T &m2);
// class definition
template<int N>
class Matrix{
template<typename T>
friend Matrix<N> operator* (const Matrix<N> &m1, const T &m2);
};
// friend function definition
template<typename T, int N> Matrix<N> operator*(const Matrix<N> &m1, const T &m2)
{
return m1; // just as an example
}
如果我编译:
Matrix<3> m;
m * 1.0;
我会收到以下链接器错误:
test.cc:(.text+0x1c7): undefined reference to `Matrix<3> operator*<double>(Matrix<3> const&, double const&)'
collect2: error: ld returned 1 exit status
答案 0 :(得分:3)
您的实物不匹配。
您的初始声明和后续定义具有以下签名:
template<typename T, int N>
Matrix<N> operator*(const Matrix<N> &m1, const T &m2);
这是一个具有两个模板参数的功能模板:T
和N
。
但是,在您的班级中,您将具有以下签名的功能模板作为朋友制作了一个
template<typename T>
friend Matrix<N> operator* (const Matrix<N> &m1, const T &m2);
这只有一个一个模板参数:T
。 N
已在此处固定。这个朋友声明也声明了这个函数模板。这是一个更好的匹配,但实际上没有定义,因此可以看到您的行为。
我认为您有两种选择。
删除operator*
的命名空间范围声明,然后在operator*
的定义内声明并定义友好的Matrix
。
更改好友声明以匹配命名空间范围声明:
template<typename T, int M>
friend Matrix<M> operator* (const Matrix<M> &m1, const T &m2);
(1)通常是更好的选择-不涉及在全局范围内添加更多operator*
,这对于编译时很有用。