模板类中的朋友功能

时间:2012-08-29 22:11:19

标签: c++ templates friend

我正在尝试使乘法运算符成为名为TVector3的模板类的朋友。我已经读过,我可以在类声明中声明它之前进行友元函数的前向声明,但是我这样做的尝试是徒劳的。我知道我可以简单地定义友元函数而不是声明它,但我希望它能用于前向声明技术。

特别是我试图为我的案例实施this解决方案。我发现this帖子也是David Rodriguez给出了一个解决方案(第三个版本),但我不知道我做错了什么。

我使用' g ++ template.cpp tempmain.cpp a '编译,编译器(g ++)给出以下错误:

对'ray :: TVector3 ray :: operator *(float,ray :: TVector3 const&)'

的未定义引用

代码如下:

template.h:

#ifndef TVECTOR_H
#define TVECTOR_H

#include <cmath>

namespace ray
{
    //forward declarations
    template <class T> class TVector3;
    template <class T> TVector3<T> operator* (T, const TVector3<T> &);

    template <class T>
    class TVector3 {

        public:
            union {
                struct {
                    T x, y, z;
                };
                T xyz[3];
            };

        //function needed
        friend TVector3<T> operator*<T> (T, const TVector3<T> &);
    };

}

#endif

template.cpp:

#include "template.h"

using namespace ray;

//friend operator function
template<class T> TVector3<T> operator * (T f, const TVector3<T> &v)
{
    return TVector3<T>(f * v.x, f * v.y, f * v.z);
}

//instantiate template of type float
template class TVector3<float>;

tempmain.cpp:

#include <iostream>
#include "template.h"

int main()
{
    ray::TVector3<float> v1, v2;

    v2.x = 3;
    v1 = 4.0f * v2; //this reports as undefined

    std::cout << v1.x << "\n";

    return 0;
}

这是完整的源代码。我做错了什么?

2 个答案:

答案 0 :(得分:4)

作为一般经验法则,应在标题中定义模板。如果在cpp文件中定义它们,则需要手动实例化模板。您正在为类模板执行此操作,但您没有实例化operator*模板。

template TVector3<T> operator*<T> (T, const TVector3<T> &);

此外,我建议您使用非模板免费函数,而不是使用模板operator*,方法是在类模板中声明并定义它:

template <class T>
class TVector3 {
//function needed
    friend TVector3<T> operator*(T f, const TVector3<T> & v) {
       return TVector3<T>(f * v.x, f * v.y, f * v.z);
    }
};

这具有免费功能(它允许第一个参数的转换)和模板(它将按需生成自由功能 - 无需手动提供所有实现)以及有限的可见性(它只能通过ADL查找

答案 1 :(得分:0)

你应该显式地实例化operator *,它就像这样工作

using namespace ray;

//friend operator function
template<class T> TVector3<T> ray::operator * (T f, const TVector3<T> &v)
{
    return TVector3<T>(f * v.x, f * v.y, f * v.z);
}

//instantiate template of type float
template class TVector3<float>;
template TVector3<float> ray::operator*<float>( float, TVector3<float> const& );

请记住,如果您编写operator*代替ray::operator*编译器,则无法知道您的意思是ray::operator*并且您没有在全局命名空间中声明新的运算符!

并且不要忘记定义TVector3( T x_, T y_, T z_ ):)