当从函数调用传递值时,std::tie 失败并返回 "cannot bind non-const lvalue reference"

std::tie fails with "cannot bind non-const lvalue reference" when passed value from a function call

我希望这段代码可以工作,但它没有编译:

#include <tuple>

struct S
{
    int x = 0;
    int y() const { return 1; }
};

bool f(const S& a, const S& b)
{
    return std::tie(a.x, a.y()) < std::tie(b.x, b.y());
}

海湾合作委员会 9 说:

error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'

return std::tie(a.x, a.y()) < std::tie(b.x, b.y());
                     ~~~^~

代码有什么问题,如何修复,为什么?我正在尝试编写一个简洁的比较函数,通常 std::tie 支持它(实际上这是 std::tie 的教科书用例)。

演示:https://godbolt.org/z/cWbQC0

std::tie 总是需要参数的左值,因为它的预期目的是在赋值中使用。要处理其他值类别,可以使用 std::forward_as_tuple:

bool f(const S& a, const S& b)
{
    return std::forward_as_tuple(a.x, a.y()) < std::forward_as_tuple(b.x, b.y());
}

这两个元组现在包含绑定到 S::y 调用结果的右值引用。不用说,在使用它时最好注意对象的生命周期。

std::tie 将左值引用作为参数,因此 S::y 返回的 int 无法绑定。您可以使用完美的转发版本 std::forward_as_tuple,而不是:

#include <tuple>

struct S
{
    int x = 0;
    int y() const { return 1; }
};

bool f(const S& a, const S& b)
{
    return std::forward_as_tuple(a.x, a.y()) < std::forward_as_tuple(b.x, b.y());
}

Demo.