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

4

我有一个代表2D向量的Vector类。它是模板化的,可以使用任何数字类型来用于xy组件。例如,我重载的算术运算符之一是*,用于将向量乘以标量:

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);
}

我还有一个函数,参数顺序相反,以允许“scalar * Vector ”加上“Vector * scalar”。如您所见,我使用的是“<T,U>”而不是简单的“<T>”,以便标量不必与向量类型相同。当我没有这样做时,令人惊讶的是,“Vector<double> * int”无法编译(我认为int会自动扩展)。无论如何,我不只是想返回一个“Vector<T>”。我想模仿内置类型并返回更高精度的那个,“T”或“U”。因此,例如,“Vector<int> * double => Vector<double>”,而“Vector<double> * short => Vector<double>”。这可能吗?
2个回答

6

您可以使用common_typedecltype来创建一个返回结果类型的函数;接下来需要创建实际的向量:

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;
}

使用 decltype,你可以通过以下方式获得结果类型:

decltype(std::declval<A>() * std::declval<B>())

对于std::common_typestd::declval,您需要#include <type_traits>
使用延迟返回类型(auto->),您可以直接在函数参数上使用decltype,但是使用std::declval感觉更加卫生,因为它不需要您提供实际的类型实例(因此即使在这种情况下不可能也可以应用)。

1
我以前没见过common_type!这真是太方便了。 - Flexo
declval 看起来也很方便,加一。 - Seth Carnegie
顺便说一下,我在谈论我的自己的数学向量类,而不是std::vector,但这仍然是一个很好的答案。不幸的是,当我#include <type_traits>时出现错误,所以我想这对我来说行不通。 - mk12
需要注意的是,这个答案需要使用C++11;如果OP被限制在C++03上,那么这里就没有太多帮助了。 - ildjarn
@Mk12:这些特性只是C++11的一部分,因此在GCC中添加-std=c++0x,或使用MSVS 10及以上版本。 - Kerrek SB
好老的C++,做同样的事情有4种方法...我最喜欢common_type解决方案,但它对我不可用。尽管如此,这个答案同样值得被接受。 - mk12

4

有两种解决方案。在 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.并且了解很多专业术语,那么你可以使用它来查找返回类型,例如:

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);
}

另外,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);
}

这使您可以使用decltype作为函数的返回类型,根据vector.x * scalar自然提升的结果来设置它。


2
太棒了,希望我能多次点赞。我一直看到->返回类型语法的好应用。 - Seth Carnegie
3
当然要注意,在C++11中,你的返回类型不应该是const,因为它会抑制移动语义。 - ildjarn
clang++ 3.0 支持这个吗? - mk12
1
没错,当我使用 clang++ -std=c++0x 时,你最后的例子编译通过了 :). - mk12
2
@Mk12:《Effective C++》一书早在C++11之前就已经出版了;如果有新版的话,这个建议肯定会被删除。 - ildjarn
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接