不使用模板为用户定义的运算符调用隐式构造函数

时间:2014-12-23 03:53:29

标签: c++ templates

在我的代码中,我实现了Vector3的模板,如下所示:

template <typename T>
struct TVector3{
    TVector3(const T& x, const T& y, const T& z);   // normal constructor from x,y,z
    TVector3(const T& val);   // construct from a constant value
    // .. other implementation
    T x, y, z;
};
// and my overload operator+ for TVector3
template <typename T>
const TVector3<T> operator+(const TVector3<T>& lhs, const TVector3<T>& rhs)
{
    return TVector3<T>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
}

我期待这样的电话:(1,2,3)+ 1 =(2,3,4),所以我这样写了:

TVector3<float> v(1, 2, 3);
v + 1.0f;   // error, on operator "+" matches ... operand types are: TVector3<float> + float

然后我似乎明白模板推导应该完全匹配参数类型而不是转换它们,所以有没有办法告诉编译器将T转换为TVector3?我不想写下面的2个重载,因为代码会变大:

template <typename T>
const TVector3<T> operator+(const TVector3<T>& lhs, const T& rhs);
template <typename T>
const TVector3<T> operator+(const T& rhs, const TVector3<T>& rhs);

感谢您的帮助!

1 个答案:

答案 0 :(得分:5)

这里的技巧是在实例化类模板时实例化一个实际上不是成员的函数。这可以通过朋友定义(内联朋友)来完成。实例化类模板时,也会实例化好友,并将其作为非模板化函数注入周围的命名空间(以受限制的方式),以便应用转换。 (我也做了返回非const,因为我不认为你打算这样做。)有关详细信息,请查找&#34;朋友姓名注入&#34;,&#34;参数依赖查找&#34;,以及相关的Barton-Nackman技巧。

template <typename T>
struct TVector3{
    friend TVector3<T> operator+(const TVector3<T>& lhs, const TVector3<T>& rhs) {
        return TVector3<T>(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
    }
    TVector3(const T& x, const T& y, const T& z);   // normal constructor from x,y,z
    TVector3(const T& val);   // construct from a constant value
    // .. other implementation
    T x, y, z;
};

int
main() {

    TVector3<float> v(1, 2, 3);
    v + 1.0f; // Works.
}

需要注意的一个重要且相关的事情是模板函数和非模板函数之间存在差异,即使签名是相同的

template <typename T> class A;

void f(A<int>); // 1

template <typename T>
void f(A<T>); // 2

template <typename T>
class A {
  friend void f(A<T>); // Makes 1 a friend if T == int, but not 2.
  friend void f<>(A<T>); /// Makes 2 also a friend.
};