【问题标题】:C++ 11 operator overload with return type deduction [closed]带有返回类型推导的 C++ 11 运算符重载
【发布时间】:2015-12-31 12:59:12
【问题描述】:

我有一个依赖于一种类型的模板类(例如template <typename T> class Vector)。现在,我想重载算术运算符:

  • 我可以将它们与用两种不同类型实例化的向量一起使用;
  • 结果推导方式与模板实例类型相同;

例子:

Vector<float> fv = {1.5, 2.5};
Vector<int> iv = {1,2};
auto s1 = fv + iv;   // s1 MUST be of type Vector<float> == {2.5, 4.5}
auto s2 = iv + fv;   // s2 MUST be of type Vector<float> == {2.5, 4.5}

我认为,在实现矩阵、向量、多项式等的通用数学库中,这将是一个在可用性方面产生差异的功能。

我找到了三种使用 C++11 获得此结果的方法

  1. -&gt; 表示法

    template <typename T, typename U>
    auto operator +(const Vector<T> &lhs, const Vector<U> &rhs)
        -> Vector<decltype(lhs[0]+rhs[0])>
    {
        Vector<decltype(lhs[0]+rhs[0])> res(lhs);
        res += rhs;
        return res;
    }
    
  2. declval

    template <typename T, typename U> 
    Vector<decltype(std::declval<T>()+std::declval<U>())> 
    operator +(const Vector<T> &lhs, const Vector<U> &rhs)
    {
        Vector<decltype(lhs[0]+rhs[0])> res(lhs);
        res += rhs;
        return res;
    }
    
  3. declval 作为默认类型 arg

    template <typename T, typename U, 
              typename R = decltype(std::declval<T>()+std::declval<U>())> 
    Vector<R> operator +(const Vector<T> &lhs, const Vector<U> &rhs)
    {
        Vector<R> res(lhs);
        res += rhs;
        return res;
    }
    

在您看来,实现此类功能的最佳方法是什么? 如果有第四个更好的解决方案,我将不胜感激。

您认为这种“互通”运算符是一项有价值的功能吗?

感谢和最好的问候, 大卫

【问题讨论】:

  • 与您的实际问题无关,但使用return res;,而不是return std::move(res);。前者允许NRVO,如果 NRVO 由于某种原因没有被使用,它仍然会隐式移动,从不复制。
  • 另外,std::move 肯定会返回 Vector&lt;T&gt;&amp;&amp;,但是您的返回类型声明为 Vector&lt;T&gt;?
  • @Eric 不,那部分是正确的。返回Vector&lt;T&gt;&amp;&amp; 意味着返回一个对函数本地对象的引用,该对象在函数返回后不能再使用。
  • 由于 Vector&lt;T&gt; 的邪恶特化,这 2 个计算类型在 sn-p 2 中可能不同。计算类型的第三种方法是 std::common_type&lt;T, U&gt;

标签: c++ templates c++11 decltype type-deduction


【解决方案1】:

这样的运算符是否是一个“好主意”取决于您的用例。但如果你想实现它们,我建议你使用从std::common_type 派生的特征类来获得更多控制:

template<typename T, typename U>
struct VectorCommonType : std::common_type<T,U> {};

template<typename T, typename U>
using VectorCommonTypeT = Vector<typename VectorCommonType<T,U>::type>;

这样您(或该课程的用户)可以在需要时对其进行专门化。像这样使用它:

template<typename T, typename U> 
VectorCommonTypeT<T,U> operator+(const Vector<T> &lhs, const Vector<U> &rhs)
{
    VectorCommonTypeT<T,U> res(lhs);
    res += rhs;
    return res;
}

【讨论】:

  • 在某些情况下这样的功能被认为是一个坏主意或坏设计?
  • @Davide 是的,这些情况是存在的。例如,如果您只是不想意外混合类型。它可能会导致更多的实例化(Vector 和其他类),这可能会导致代码膨胀、指令缓存失效等。在嵌入式环境中,这可能是一个真正的问题。 没有具有上述运算符可能有助于在编译时捕获它们。
  • VectorCommonType 在这里的作用是什么?为什么要创建 std::common_type 的无操作子类?
  • @Eric 正如我所说,它允许您在需要时添加专业化。没有它,您将不得不专门化std::common_type,但这也可能用于其他目的,因此您将没有Vector 的有限范围。
猜你喜欢
  • 2015-01-29
  • 1970-01-01
  • 2013-03-15
  • 2015-06-03
  • 2021-03-05
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 2012-04-26
相关资源
最近更新 更多