C++ 是否有任何理由使用右值引用重载运算符?

C++ 是否有任何理由使用右值引用重载运算符?,c++,c++11,optimization,rvalue-reference,C++,C++11,Optimization,Rvalue Reference,有一个模板化的向量类(关于数学,而不是容器)。我需要让普通的数学运算负担过重。像这样超载有什么意义吗: template <typename T, size_t D> Vector<T, D> operator+(const Vector<T, D>& left, const Vector<T, D>& right) { std::cout << "operator+(&, &)" <<

有一个模板化的向量类(关于数学,而不是容器)。我需要让普通的数学运算负担过重。像这样超载有什么意义吗:

template <typename T, size_t D>
Vector<T, D> operator+(const Vector<T, D>& left, const Vector<T, D>& right)
{
    std::cout << "operator+(&, &)" << std::endl;
    Vector<T, D> result;

    for (size_t i = 0; i < D; ++i)
        result.data[i] = left.data[i] + right.data[i];

    return result;
}

template <typename T, size_t D>
Vector<T, D>&& operator+(const Vector<T, D>& left, Vector<T, D>&& right)
{
    std::cout << "operator+(&, &&)" << std::endl;
    for (size_t i = 0; i < D; ++i)
        right.data[i] += left.data[i];

    return std::move(right);
}

template <typename T, size_t D>
Vector<T, D>&& operator+(Vector<T, D>&& left, const Vector<T, D>& right)
{
    std::cout << "operator+(&&, &)" << std::endl;
    for (size_t i = 0; i < D; ++i)
        left.data[i] += right.data[i];

    return std::move(left);
}
template <typename T, size_t D>
class Vector
{
   T data[D];
   // ...
};
两个右值引用有问题,但我认为这无关紧要


我为什么要这么做?由于性能方面的原因,理论上,在不创建新对象的情况下,它会工作得更快一点,但它会吗?也许编译器会使用
运算符+(const Vector&left,const Vector&right)
优化简单代码,如果向量的移动成本低于复制成本(通常情况下,它在内部存储指向可以廉价复制的数据的指针),则没有任何理由重载右值?

而对于rvlaue引用使用重载将有助于提高性能。您可以查看
std::string
,以及它如何在两个参数中重载所有类型的可能引用:

编辑


因为OP阐明了内部数据表示是c样式的数组,所以提供多个重载没有任何好处。C样式数组的移动成本不低-它们是复制的-因此这些多个重载没有任何作用。

这取决于您对
Vector
的实现:

  • 如果类的移动速度快于复制速度,那么为移动提供额外的重载可能会提高性能
  • 否则,提供重载应该不会更快
在一篇评论中,您提到
Vector
如下所示:

template <typename T, size_t D>
Vector<T, D> operator+(const Vector<T, D>& left, const Vector<T, D>& right)
{
    std::cout << "operator+(&, &)" << std::endl;
    Vector<T, D> result;

    for (size_t i = 0; i < D; ++i)
        result.data[i] = left.data[i] + right.data[i];

    return result;
}

template <typename T, size_t D>
Vector<T, D>&& operator+(const Vector<T, D>& left, Vector<T, D>&& right)
{
    std::cout << "operator+(&, &&)" << std::endl;
    for (size_t i = 0; i < D; ++i)
        right.data[i] += left.data[i];

    return std::move(right);
}

template <typename T, size_t D>
Vector<T, D>&& operator+(Vector<T, D>&& left, const Vector<T, D>& right)
{
    std::cout << "operator+(&&, &)" << std::endl;
    for (size_t i = 0; i < D; ++i)
        left.data[i] += right.data[i];

    return std::move(left);
}
template <typename T, size_t D>
class Vector
{
   T data[D];
   // ...
};
在重载版本中,您可以就地更新:

template <typename T, size_t D>
Vector<T, D>&& operator+(const Vector<T, D>& left, Vector<T, D>&& right)
{
    std::cout << "operator+(&, &&)" << std::endl;
    for (size_t i = 0; i < D; ++i)
        right.data[i] += left.data[i];

    return std::move(right);
}
模板
向量和运算符+(常量向量和左、向量和右)
{

std::我不太清楚你的问题是什么。如果你想知道编译器可以优化什么,你可以随时查看它的输出,例如,模板函数中的
&&
与非模板函数中的
&&
不同。模板函数中的
&&
是一个转发引用(引用折叠规则适用);
&&
在非模板函数中是右值引用,不进行折叠。您有转发引用。@Richard:只有参数的形式为T&&,在
foo
的情况下(这里就是这种情况)这是一个实际的r值参考。@DrewDormann,是的,我提到过it@devalone右值引用可以引用任何对象,而不仅仅是临时对象。此外,如果它是临时数据,并且用户写入
auto&&result=x+temporary()
那么结果是一个悬空引用,因为它引用的是现在已死亡的临时变量。我的向量就是这样定义的简单数组
T data[D]
它将只用于简单类型,如int、double等,我认为向量的大小不会大于4。我想使用右值重载的原因是为了防止创建额外的对象。数组的移动不能比复制慢,所以它不应该使程序变慢。我想使用右值重载的原因是为了防止在函数中创建额外的对象,但正如您所提到的,有返回值优化,但当我试图用-O4在gcc中编译时,优化无法实现。
template <typename T, size_t D>
Vector<T, D>&& operator+(const Vector<T, D>& left, Vector<T, D>&& right)
{
    std::cout << "operator+(&, &&)" << std::endl;
    for (size_t i = 0; i < D; ++i)
        right.data[i] += left.data[i];

    return std::move(right);
}