如评论中所述,您的朋友函数声明
friend Vector4<T> operator*(const Vector4<T>& l, const Vector4<T>& r);
在全局命名空间中声明一个非模板函数。例如,当您实例化Vector4<int>
该函数时
Vector4<int> operator*(const Vector4<int>& l, const Vector4<int>& r)
被宣布。请注意,它不是函数模板。(另见 [temp.friend])
然后你Vector4.inl
声明并定义了一个函数模板
template<typename T>
Vector4<T> operator*(const Vector4<T>& l, const Vector4<T>& r)
即前一个功能的重载。在表达式a * b
中,重载决议选择非模板operator*
而不是模板版本(参见 [over.match.best]/1)。这会导致链接器错误,因为尚未定义非模板函数。
正如我几乎自欺欺人一样,简短的评论:
template<typename T>
Vector4<T> operator*(const Vector4<T>& l, const Vector4<T>& r);
由于这个操作符是一个自由函数(一个非成员函数),这两行声明了一个函数模板,很像
template<typename T>
Vector4<T> wup();
另一方面,
template<typename T>
Vector4<T> Vector4<T>::operator*(const Vector4<T>& r)
{ /* ... */ }
定义类模板 ( ) 的成员函数(非模板Vector4
)。
一种解决方案是使用前向声明并仅与特定专业化友好:
template<typename T>
class Vector4;
template<typename T>
Vector4<T> operator*(const Vector4<T>& l, const Vector4<T>& r);
template<typename T>
class Vector4
{
public:
T X;
T Y;
T Z;
T W;
Vector4();
Vector4(T X, T Y, T Z, T W);
~Vector4();
// compiler knows of some function template `operator*`,
// can name an specialization:
// ~~~~~~~~~~~~~~~~~~~~~~~~vvv
friend Vector4<T> operator*<T>(const Vector4<T>& l, const Vector4<T>& r);
};
template<typename T>
Vector4<T>::Vector4()
{
X = 0;
Y = 0;
Z = 0;
W = 0;
}
template<typename T>
Vector4<T>::Vector4(T X, T Y, T Z, T W)
{
this->X = X;
this->Y = Y;
this->Z = Z;
this->W = W;
}
template<typename T>
Vector4<T>::~Vector4()
{}
template<typename T>
Vector4<T> operator*(const Vector4<T>& l, const Vector4<T>& r)
{
return(Vector4<T>(l.X * r.X, l.Y * r.Y, l.Z * r.Z, l.W * r.W));
}
int main()
{
Vector4<float> a, b;
a = a * b;
}
另一种解决方案是与整个operator*
模板而不是单个专业化:
template<typename U>
friend Vector4<U> operator*(Vector4<U> const&, Vector4<U> const&);