1

假设我有这个课程:

Vector4.h中:

#pragma once

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();

friend Vector4<T> operator*(const Vector4<T>& l, const Vector4<T>& r);
};

#include "Vector4.inl"

Vector4.inl中:

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));
}

当我在这样的地方使用它时:

Vector4<float> a, b;
a = a * b;

它给了我一个LNK2019 未解析的外部符号 我做错了什么?我使用的语法不正确吗?

4

3 回答 3

4

如评论中所述,您的朋友函数声明

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&);
于 2013-07-24T18:50:13.337 回答
1

我能够将代码更改为非友好版本:

  1. 类定义中的代码:

    Vector4<T> operator*(Vector4<T> const & r);
    
  2. 运营商代码*。改为只取一个参数。

    template<typename T>
    Vector4<T> Vector4<T>::operator*(Vector4<T> const &r)
    {
         return(Vector4<T>(this->X * r.X, this->Y * r.Y, this->Z * r.Z, this->W * r.W));
    }
    
于 2013-07-24T18:50:33.873 回答
0

首先从.h 文件中friend的声明中删除operator*

它应该是这样的:

Vector4<T> operator*(const Vector4<T>& r);

然后在 .inl 文件中 operator* 应该是这样的:

Vector4<T> Vector4<T>::operator*(const Vector4<T>& r){
     return(Vector4<T>(X * r.X, Y * r.Y, Z * r.Z, W * r.W));
}

运算符左侧的操作数就是所谓的这个成员函数。

于 2013-07-24T19:06:37.470 回答