C++ 模板类自动类型转换的运算符重载

C++ 模板类自动类型转换的运算符重载,c++,templates,vector,C++,Templates,Vector,我有一个模板类,我正在重载该类的操作符+,但需要它可能返回与该类实例化时不同的数据类型。例如,以下代码段执行向量*向量(内积)、向量*标量或标量*向量的标准数学定义。具体来说,假设我有一个向量,标量的类型是double——我想从“Vector*scalar”操作符+函数返回一个double 我很确定我缺少了一些friend函数(?)的模板语句,但这段代码不是用来编译的 template<class T> class Vector { private: std::vector&

我有一个模板类,我正在重载该类的
操作符+
,但需要它可能返回与该类实例化时不同的数据类型。例如,以下代码段执行向量*向量(内积)、向量*标量或标量*向量的标准数学定义。具体来说,假设我有一个
向量
,标量的类型是
double
——我想从“Vector*scalar”
操作符+
函数返回一个double

我很确定我缺少了一些friend函数(?)的
模板
语句,但这段代码不是用来编译的

template<class T>
class Vector
{
private:
    std::vector<T> base;

public:
    friend Vector operator*(const Vector& lhs, const Vector& rhs);  // inner product    
    Vector<T> operator*(const T scalar);  // vector*scalar   
    friend Vector operator*(const T scalar, const Vector& rhs);  // scalar*vector
};

template<class T>
Vector<T> operator*(const Vector<T>& lhs, const Vector<T>& rhs)  // inner product
{
    assert( lhs.base.size() == rhs.base.size() );

    Vector result;
    result.base.reserve(lhs.base.size());
    std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );

    return result;
}

template<class T>
Vector<T> Vector<T>::operator*(const T scalar)  // vector*scalar
{
    Vector result;
    result.base.reserve(base.size());

    std::transform( base.begin(), base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );

    return result;
}

template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs)  // scalar*vector
{
    Vector result;
    result.base.reserve(rhs.base.size());

    std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );

    return result;
}
模板
类向量
{
私人:
std::向量基;
公众:
友元向量运算符*(常数向量和lhs,常数向量和rhs);//内积
向量运算符*(常量T标量);//向量*标量
友元向量运算符*(常量T标量、常量向量和rhs);//标量*向量
};
模板
向量运算符*(常量向量和lhs,常量向量和rhs)//内积
{
断言(lhs.base.size()==rhs.base.size());
矢量结果;
result.base.reserve(lhs.base.size());
std::transform(lhs.base.begin()、lhs.base.end()、rhs.base.begin()、std::back_inserter(result.base)、std::multiplies());
返回结果;
}
模板
向量向量::运算符*(常量T标量)//向量*标量
{
矢量结果;
result.base.reserve(base.size());
std::transform(base.begin()、base.end()、std::back_插入器(result.base)、std::bind1st(std::multiplies()、scalar));
返回结果;
}
模板
向量运算符*(常量T标量、常量向量和rhs)//标量*向量
{
矢量结果;
result.base.reserve(rhs.base.size());
std::transform(rhs.base.begin()、rhs.base.end()、std::back_插入器(result.base)、std::bind1st(std::multiplies()、scalar));
返回结果;
}

您可以添加更多模板参数,例如:

template<class T, class S>
Vector<S> Vector<T>::operator*(const S scalar)
模板
向量向量::运算符*(常数S标量)

并确保在函数体中的正确位置对标量类型使用
S
,对向量元素类型使用
T

友元声明应如下所示:

template<class S>
class Vector
{
private:
    std::vector<S> base;

public:
    template<class T> friend T operator*(const Vector<T>& lhs, const Vector<T>& rhs);  // inner product    
    template<class T> friend Vector<T> operator*(const T scalar);  // vector*scalar   
    template<class T> friend Vector<T> operator*(const T scalar, const Vector<T>& rhs);  // scalar*vector
};
template<class T>
T operator*(const Vector<T>& lhs, const Vector<T>& rhs)  // inner product
{
    assert( lhs.base.size() == rhs.base.size() );

    Vector<T> result;
    result.base.reserve(lhs.base.size());
    std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );

    return result;
}

template<class T>
Vector<T> operator*(const Vector<T>& lhs, const T scalar)  // vector*scalar
{
    return scalar*lhs;
}

template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs)  // scalar*vector
{
    Vector<T> result;
    result.base.reserve(rhs.base.size());

    std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );

    return result;
}
模板
类向量
{
私人:
std::向量基;
公众:
模板友元T运算符*(常量向量和lhs,常量向量和rhs);//内积
模板友元向量运算符*(常量T标量);//向量*标量
模板友元向量运算符*(常量T标量、常量向量和rhs);//标量*向量
};
其余代码如下所示:

template<class S>
class Vector
{
private:
    std::vector<S> base;

public:
    template<class T> friend T operator*(const Vector<T>& lhs, const Vector<T>& rhs);  // inner product    
    template<class T> friend Vector<T> operator*(const T scalar);  // vector*scalar   
    template<class T> friend Vector<T> operator*(const T scalar, const Vector<T>& rhs);  // scalar*vector
};
template<class T>
T operator*(const Vector<T>& lhs, const Vector<T>& rhs)  // inner product
{
    assert( lhs.base.size() == rhs.base.size() );

    Vector<T> result;
    result.base.reserve(lhs.base.size());
    std::transform( lhs.base.begin(), lhs.base.end(), rhs.base.begin(), std::back_inserter(result.base), std::multiplies<T>() );

    return result;
}

template<class T>
Vector<T> operator*(const Vector<T>& lhs, const T scalar)  // vector*scalar
{
    return scalar*lhs;
}

template<class T>
Vector<T> operator*(const T scalar, const Vector<T>& rhs)  // scalar*vector
{
    Vector<T> result;
    result.base.reserve(rhs.base.size());

    std::transform( rhs.base.begin(), rhs.base.end(), std::back_inserter(result.base), std::bind1st(std::multiplies<T>(), scalar) );

    return result;
}
模板
T运算符*(常数向量和lhs,常数向量和rhs)//内积
{
断言(lhs.base.size()==rhs.base.size());
矢量结果;
result.base.reserve(lhs.base.size());
std::transform(lhs.base.begin()、lhs.base.end()、rhs.base.begin()、std::back_inserter(result.base)、std::multiplies());
返回结果;
}
模板
向量运算符*(常量向量&lhs,常量标量)//向量*标量
{
返回标量*lhs;
}
模板
向量运算符*(常量T标量、常量向量和rhs)//标量*向量
{
矢量结果;
result.base.reserve(rhs.base.size());
std::transform(rhs.base.begin()、rhs.base.end()、std::back_插入器(result.base)、std::bind1st(std::multiplies()、scalar));
返回结果;
}

我猜您想要的是返回一个向量,其值类型是每组件操作返回的类型,而不一定是标量的类型

例如:

Vector<int>    * int    -> Vector<int>
Vector<int>    * double -> Vector<double>
Vector<double> * int    -> Vector<double>
Vector<char>   * float  -> Vector<float>
有趣的是

T3 = decltype(std::declval<T1>() * std::declval<T2>())

如中所示。

编译器错误消息是什么?我猜您想要返回的是一个向量,其值类型是每个组件操作返回的类型,即
int*double
产生的结果,在本例中是
double
而不是
int
。这在
decltype
中是可能的。谢谢,但是有没有办法做到这一点,使结果总是两种数据类型中的“高”一个,无论是向量还是标量?看起来这只会返回标量对象的数据类型,但是如果向量是双精度的,标量是int呢?@David是的,请看我的答案。谢谢。将第二个“vector*scalar”声明为友元有什么好处吗?即使它将在类的对象上调用?谢谢!将这种类型的东西内联声明是否被认为是良好的实践?(我想这就是你所拥有的)另外,我在我的代码中注意到,在
操作符+
定义中,我从未为
向量结果
声明一个类型,例如,我没有编写
向量结果
,但它的原始代码是有效的。类型是隐式分配的吗?关于你的第一条评论:我不知道你在这种情况下使用“inline”是什么意思。运算符定义的代码应该放在标题中,并且始终是内联的,因为它是一个模板,就像类的其他部分一样。不管您是先声明,然后定义(在同一个头文件中),还是同时执行这两件事。关于您的第二条评论:对于成员函数,您可以编写
Vector
而不是
Vector
,这是等效的。但对于非成员,这将不起作用,您必须像在我的代码片段中一样明确。再次感谢。当我尝试使用您的想法进行编译时,我遇到了一个错误,但这可能与我在类声明中声明函数的方式有关,而不是与定义有关。我声明了一个这样的函数,如
模板友元向量操作符+(constvector&lhs,constvector&rhs)
给出错误“默认模板参数只允许在类模板上使用”。有什么想法吗?哦,我刚才看到您使用了
std::multiples
,它为相同的
T
计算
T*T
!不能将此函子用于此操作。你可以用兰姆达。此外,当标量位于右侧时,应该绑定标量