简体   繁体   English

C ++算术运算符重载 - 自动扩展?

[英]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. 模板允许任何数字类型用于xy分量。 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 . 我想模仿内置类型并返回具有更高精度的TU 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_typedecltype来做一些能够得到结果类型的东西; 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_typestd::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM