不能使函数接受右值和左值引用

Can't make a function accept both rvalue and lvalue references

class Vec3{

private:
    float x, y, z;

public:
    Vec3() = default;
    Vec3(const float c) {x = c; y = c; z = c;}

    static  Vec3& normalize(Vec3& v) {/* normalize */ return v;}

};

Vec3 aaa = Vec3( 1.0f);
Vec3 bbb = Vec3::normalize( Vec3( 1.0f));
Vec3 ccc = Vec3::normalize( aaa);

我想编写以向量为参数的函数,对它们进行一些处理并return它们作为参考。

在上面的代码中,bbb 将无法编译,因为它是对右值的非常量引用。我无法将其设为 const,因为 normalize 需要修改对象。如果我让函数接受右值引用 (Vec3&& v),那么 ccc 将无法编译,因为 aaa 是一个左值。我可以不用编写两个版本的 normalize 来完成这项工作吗?

(我对右值和左值引用感到困惑,例如我不明白为什么 someFunc(const Vec3& v) 会同时接受右值和左值,而非常量版本不会。)

不,你不能。你必须使用两个版本。您可以按照@NathanOliver 的建议将它们组合起来,但您仍然需要两个版本。

I don't understand for example why a someFunc(const Vec3& v) will accept both rvalues and lvalues while the non-const version won't.

因为标准禁止将右值绑定到非常量左值引用。这与

中的问题相同
const int& x = 1;  // OK
int& y = 2;  // error

似乎该标准试图保护您免受临时文件的意外修改。不幸的是,我真的不能给你更深入的解释。但是你可以阅读这个:

Why not non-const reference to temporary objects?

How come a non-const reference cannot bind to a temporary object?

当然,最后 && 的发明正是为了实现这一点。所以我猜这更像是历史原因?

您只需花费一点开销即可完成此操作。您不必编写规范化代码两次,但您需要以不同方式处理 returning,因为您不想 return 对右值的引用。

如果你有类似的东西

static  Vec3& normalize(Vec3& v) {/* normalize */ return v;}
static  Vec3 normalize(Vec3&& v) { return normalize(v);}
                                                    ^ v is a lvalue here

现在您可以将临时文件转发到左值引用版本,然后 return 按值转发,这样您就不会尝试引用可能不再存在的对象。