【问题标题】:Mixing Templated Argument Types混合模板化参数类型
【发布时间】:2016-06-24 15:46:58
【问题描述】:

如何在 C++ 模板/泛型编程和重载运算符中处理混合数据类型?

例如,假设我们正在创建一个带有 x 和 y 参数的二维坐标类,并且我们想要添加它们:

template <class T>
class Cartesian {
public:
    Cartesian();
    Cartesian(T _x, T _y);
    Cartesian<T> operator + (const Cartesian<T> & rhs);
    // setters, getters
private:
    T x, y;
};

+运算符重载添加两个坐标:

template <class T>
Cartesian<T> Cartesian<T>::operator + (const Cartesian<T> & rhs) {return Cartesian(x+rhs.x,y+rhs.y);}

现在,我们实例化四个点:两个具有int 系数;另外两个float:

int main() {
    Cartesian<int> i1(1,2), i2(3,4);
    Cartesian<float> f1(5.7, 2.3), f2(9.8, 7.43);

添加两个整数没有问题,添加两个浮点数也是如此。但是如果我们想在浮点数中添加一个 int 呢?即使在四年级的课堂上,这也不会成为问题,但在这里......

(i1 + i2); // ok
(f1 + f2); // ok
(i1 + f2); // uh oh!!!

有没有简单的方法来处理这种情况?谢谢! :)

【问题讨论】:

  • 有不同的方法可以做到这一点。但首先你必须决定:返回类型应该是什么?
  • 您需要为Cartesian&lt;int&gt;() + Cartesian&lt;float&gt; 添加一个运算符重载。它们是两种不同的类型。
  • 乔尔这太荒谬了。如果我想在浮点数中添加双精度怎么办?变成双倍?然后将其扩展到减法、乘法等。我将定义数百个重载!

标签: c++ templates operator-overloading std generic-programming


【解决方案1】:

您可以使用免费的operator+ 重载。

template <class T, class U>
typename std::enable_if<std::is_arithmetic<T>::value && 
  std::is_arithmetic<U>::value, Cartesian<std::common_type_t<T, U>>>::type 
operator + (Cartesian<T> const & lhs, Cartesian<U> const & rhs) 
{
    return Cartesian<std::common_type_t<T, U>>(lhs.x+rhs.x,lhs.y+rhs.y);
}

如果在 C++14 之前,请将 std::common_type_t&lt;T, U&gt; 替换为 typename std::common_type&lt;T,U&gt;::type

现在你可以执行上述操作了:

Cartesian<int> i1(1, 2), i2(3, 4);
Cartesian<float> f1(5.7, 2.3), f2(9.8, 7.43);
auto a = i1 + i2; // a === Cartesian<int>
auto b = f1 + f2; // b === Cartesian<float>
auto c = i1 + f2; // c === Cartesian<float>

【讨论】:

  • 在 C++11 中,函数模板可以具有默认模板参数,因此将 enable_if 放在 template&lt;...&gt; 中会更清楚,而不是修改返回类型。
  • @Cheersandhth.-Alf 你为什么这么认为?
【解决方案2】:

我只想定义一个提供参数类型推导的工厂函数,

template< class T >
auto cartesian( T const x, T const y )
    -> Cartesian<T>
{ return {x, y}; }

然后一个独立的operator+like

template< class U, class V >
auto operator+( Cartesian<U> const& a, Cartesian<V> const& b )
{ return cartesian( a.x + b.x, a.y + b.y ); }

嗯,这很容易。

【讨论】:

  • 更简洁、更通用(如果 C++14 可用)。接受您的 +1 - 即使我不喜欢这里的尾随返回类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 1970-01-01
  • 2014-05-18
  • 1970-01-01
  • 2018-10-23
  • 1970-01-01
相关资源
最近更新 更多