[英]C++ arithmetic operator overloading—automatic widening?
I have a Vector
class which represents a 2D vector. 我有一个
Vector
类,代表一个2D矢量。 It is templated to allow any numerical type to be used for the x and y components. 模板允许任何数字类型用于x和y分量。 As an example, one of the arithmetic operators I overload is
*
for multiplying a vector with a scalar: 例如,我重载的算术运算符之一是
*
用于将向量与标量相乘:
template <typename T, typename U>
inline const Vector<T> operator*(const Vector<T>& vector, U scalar) {
return Vector<T>(vector.x * scalar, vector.y * scalar);
}
(I also have a function with the parameters in the opposite order to allow scalar * Vector
in addition to Vector * scalar
). (我还有一个函数,参数顺序相反,允许除了
Vector * scalar
之外的scalar * Vector
)。
As you can see, I use <T, U>
instead of simply <T>
so that the scalar doesn't have to be the same type as the Vector. 如您所见,我使用
<T, U>
而不是简单的<T>
因此标量不必与Vector的类型相同。 When I didn't do this, surprisingly Vector<double> * int
wouldn't compile (I thought the int would automatically widen). 当我没有这样做时,令人惊讶的是
Vector<double> * int
将无法编译(我认为int会自动加宽)。
In any case, I don't simply want to return a Vector<T>
. 无论如何,我不只是想返回一个
Vector<T>
。 I want to mimic the built-in types and return whichever has higher precision, T
or U
. 我想模仿内置类型并返回具有更高精度的
T
或U
So for example, Vector<int> * double => Vector<double>
while Vector<double> * short => Vector<double>
. 例如,
Vector<int> * double => Vector<double>
而Vector<double> * short => Vector<double>
。
Is this possible? 这可能吗?
You can use common_type
or decltype
to cook up something that gives you the resulting type; 你可以使用
common_type
或decltype
来做一些能够得到结果类型的东西; and then you have to create the actual vector: 然后你必须创建实际的矢量:
template <typename A, typename B>
std::vector<typename std::common_type<A, B>::type>
operator*(std::vector<A> const & v, B const & x)
{
std::vector<typename std::common_type<A, B>::type> res;
res.reserve(v.size());
for (A a : v) res.push_back(a * x);
return res;
}
Using decltype
, you can get at the result type via: 使用
decltype
,您可以通过以下方式获取结果类型:
decltype(std::declval<A>() * std::declval<B>())
For both std::common_type
and std::declval
you need to #include <type_traits>
. 对于
std::common_type
和std::declval
您需要#include <type_traits>
。
With delayed return types ( auto
and ->
) you can use decltype
directly on the function arguments, but using std::declval
feels a bit more hygienic, since it doesn't require you to furnish an actual instance of your type (and thus it is applicable even in situations where this isn't possible). 使用延迟返回类型(
auto
和->
),您可以直接在函数参数上使用decltype
,但使用std::declval
会感觉更卫生一些,因为它不需要您提供类型的实际实例(因此它甚至适用于不可能的情况)。
There are two solutions to this. 有两种解决方案。 In Pre C++11 you can write a template like:
在Pre C ++ 11中,您可以编写如下模板:
template <typename T, typename U>
struct WhatWillItBe {
typedef T result_t;
};
template <typename T>
struct WhatWillItBe<T, double> {
typedef double result_t;
};
// ... lots more
etc. and write a lot of specialisations, then you can use that to look up the return type, eg: 等,写了很多专业,然后你可以使用它来查找返回类型,例如:
template <typename T, typename U>
inline const Vector<typename WhatWillItBe<T,U>::result_t> operator*(const Vector<T>& vector, U scalar) {
return Vector<typename WhatWillItBe<T,U>::result_t>(vector.x * scalar, vector.y * scalar);
}
Alternatively C++11 makes this straightforward, you can write auto
for the return type and use ->
to specify the return type after the rest of the function: 或者C ++ 11使这很简单,你可以为返回类型写
auto
,并使用->
在函数的其余部分之后指定返回类型:
template <typename T, typename U>
inline auto operator*(const Vector<T>& vector, U scalar) -> Vector<decltype(vector.x*scalar)> {
return Vector<decltype(vector.x*scalar)>(vector.x * scalar, vector.y * scalar);
}
Which allows you to use decltype
for the return type of a function, setting it based on what would happen for promotion naturally with vector.x * scalar
. 这允许您使用
decltype
作为函数的返回类型,根据vector.x * scalar
自然会进行的设置来设置它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.