0

我正在尝试实现一个固定大小的数组类,它将代表小尺寸的向量。我想定义典型的向量运算,例如乘以标量并与另一个向量求和。问题是我无法使用这两个代码获得相同的性能:

for (size_t i = 0; i < N; ++i)
    vout[i] = (k[0][i] + 2*k[1][i] + 2*k[2][i] + k[3][i])/6;
// vs
vout = (k[0] + 2.0*k[1] + 2.0*k[2] + k[3])/6.0;

原因是第二个选项是在此过程中创建更多数组,而第一个选项是在原地添加。我想知道是否有一种方法可以编写一个对临时对象(r 值引用)进行操作的函数,以便在临时对象上执行求和,而无需分配额外的向量。

我当前的代码:

template<class T, int N>
class SVec {
  public:
    inline T& operator[](int i) { return mdata[i]; }
    inline const T operator[](size_t i) const { return mdata[i]; }
    inline T* data() { return mdata; }
    inline T const* data() const { return mdata; }

    inline SVec& operator+=(const SVec& rhs) {
        for (size_t i = 0; i < N; ++i) mdata[i] += rhs.mdata[i];
        return *this;
    }
    inline SVec& operator-=(const SVec& rhs) {
        for (size_t i = 0; i < N; ++i) mdata[i] -= rhs.mdata[i];
        return *this;
    }
    inline SVec& operator*=(T rhs) {
        for (size_t i = 0; i < N; ++i) mdata[i] *= rhs;
        return *this;
    }
    inline SVec& operator/=(T rhs) {
        for (size_t i = 0; i < N; ++i) mdata[i] /= rhs;
        return *this;
    }

    inline SVec& fma(const SVec& x, T y) {
        for (size_t i = 0; i < N; ++i) mdata[i] += x[i]*y;
        return *this;
    }

    inline SVec&& operator+(const SVec& rhs) && {
        for (size_t i = 0; i < N; ++i) mdata[i] += rhs.mdata[i];
        return std::move(*this);
    }
    inline SVec&& operator*(T rhs) && {
        for (size_t i = 0; i < N; ++i) mdata[i] *= rhs;
        return std::move(*this);
    }
    inline SVec&& operator/(T rhs) && {
        for (size_t i = 0; i < N; ++i) mdata[i] /= rhs;
        return std::move(*this);
    }


  private:
    T mdata[N];
};

template<typename T, int N>
inline SVec<T, N> operator+(SVec<T, N> lhs, const SVec<T, N>& rhs) {
    return lhs += rhs;
}
// Tried:
// template<typename T, int N>
// inline SVec<T, N>&& operator+(SVec<T, N>&& lhs, const SVec<T, N>& rhs) {
//     lhs += rhs;
//     return lhs;
// }
// template<typename T, int N>
// inline SVec<T, N>&& operator+(const SVec<T, N>& rhs, SVec<T, N>&& lhs) {
//     lhs += rhs;
//     return lhs;
// }
// template<typename T, int N>
// inline SVec<T, N>&& operator+(SVec<T, N>&& lhs, SVec<T, N>&& rhs) {
//     lhs += rhs;
//     return lhs;
// }
template<typename T, int N>
inline SVec<T, N> operator-(SVec<T, N> lhs, const SVec<T, N>& rhs) {
    return lhs -= rhs;
}
template<typename T, int N>
inline SVec<T, N> operator*(SVec<T, N> lhs, T rhs) {
    return lhs *= rhs;
}
tem
plate<typename T, int N>
inline SVec<T, N> operator*(T rhs, SVec<T, N> lhs) {
    return lhs *= rhs;
}
template<typename T, int N>
inline SVec<T, N> operator/(SVec<T, N> lhs, T rhs) {
    return lhs /= rhs;
}
template<typename T, int N>
inline SVec<T, N> operator/(T rhs, SVec<T, N> lhs) {
    return lhs /= rhs;
}

template<typename T, int N>
inline SVec<T, N> fma(const SVec<T, N>& x, T y, SVec<T, N> z) {
    return z.fma(x, y);
}

template<int N>
using DoubleVec = SVec<double, N>;
4

1 回答 1

0

如果我理解正确,您正在尝试返回在原始副本上修改的对象。这不能在独立的 operator+ 上完成。

但是,返回值优化的概念可能适用于您的编译器,具体取决于使用情况,如果您立即从按值返回的函数返回结果,编译器可能会对其进行优化而不将其存储在临时: 返回值优化

我可以看到您的独立 operator+ 仅接受相同的类型,因此您也可以将类似operator+(...)&的 for 作为类成员并且可以返回自身。但是这样会带来更多的问题,如下图:

    inline SVec& operator+(const SVec& rhs)& {
        for (size_t i = 0; i < N; ++i) mdata[i] += rhs.mdata[i];
        return *this;
    }

当您有这样的语句时,这将无法正常工作,但不会创建新副本。

    SVec<int, 2> s1;
    SVec<int, 2> s2;
    SVec<int, 2> s3;
    s3 = s1 + s2;
于 2020-11-14T04:42:26.503 回答