模板类自动类型转换的运算符重载
Operator Overload for Template Class Auto Type Conversion
我有一个重载operator+
的模板类,但需要它可能返回与该类实例化的数据类型不同的数据类型。例如,以下代码段执行向量*向量(内积)、向量*标量或标量*向量的标准数学定义。具体来说,假设我有一个Vector<int>
,标量的类型是double
——我想从"vector*scalar"operator+
函数返回一个double。
我很确定我遗漏了friend函数(?)的一些template<class T>
语句,但这个片段不是用来编译的。
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;
}
我想您想要的是返回一个Vector,其值类型是每个组件操作返回的类型,而不一定是标量的类型。
例如:
Vector<int> * int -> Vector<int>
Vector<int> * double -> Vector<double>
Vector<double> * int -> Vector<double>
Vector<char> * float -> Vector<float>
等等。
为此,您应该分别定义两种输入类型,比如T1
和T2
(其中一个或两个操作数是它的Vector
)。您不想简单地使用标量类型(用于向量*标量或标量*向量运算)作为结果,否则它可能会被转换(参见我的第三个示例:结果将是Vector<int>
。
以上可以使用decltype
来找到第三种(结果)类型。
为了简单起见,将操作员定义为非成员:
template<typename T1, typename T2, typename T3 = decltype(std::declval<T1>() * std::declval<T2>())>
Vector<T3> operator*(const Vector<T1>& lhs, const T2 & scalar) // inner product
{
Vector<T3> result;
//...
return result;
}
有趣的部分是
T3 = decltype(std::declval<T1>() * std::declval<T2>())
在这里,我们使用另外两个类型T1
和T2
来找到类型T3
。首先,我们构造两个值不重要的值(std::declval
函数是一个辅助函数,返回作为模板参数给定的类型)。然后我们将这些值相乘,但结果同样不重要;我们只对类型感兴趣。这就是第三部分的作用:decltype
为您提供表达式的类型(不计算)。
其他运算符可以类似地实现。
为了让这些操作员成为朋友,您需要语法
template<...> friend ...
正如丹维尔的回答所示。
友元声明应该如下所示:
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;
}
您可以添加更多的模板参数,例如:
template<class T, class S>
Vector<S> Vector<T>::operator*(const S scalar)
并确保在函数体中的正确位置使用S
作为标量类型,使用T
作为矢量元素类型。
- 使用C++中的模板和运算符重载执行矩阵运算
- 为什么这个运算符<重载函数对 STL 算法不可见?
- <T> 通过模板化运算符重载将 std::complex 乘以双倍
- C++20概念:需要运算符重载
- 使用赋值运算符重载从类中返回jobject
- 在运算符重载定义中使用成员函数(const错误)
- 字节到位运算符重载C++
- 为什么在运算符重载时需要参考?
- 类中 c++ 的运算符 + 重载
- 算术复合运算符重载为非成员
- 运算符重载 (+),用于添加两个具有 C++ 的数组
- 交换运算符 + 重载会导致无限递归
- 如何理解新的运算符重载?
- 向量保持复数的运算符重载
- 如何创建运算符重载?
- 链接列表运算符重载没有打印出我想要的内容
- C++:需要帮助了解运算符重载错误
- 使用模板化运算符重载 XOR 运算符失败
- 如何确保接受的C++模板类型使运算符重载?
- 运算符重载使用运算符+添加类模板