std::tie和std::forward_as_tuple有什么区别?

15

对于给定的类,如果我想编写所有比较运算符,为避免代码重复,我会像这样编写它们:

class B {
public:
    bool operator==(Type const& rhs) const {
        return as_tuple() == rhs.as_tuple();
    }

    bool operator!=(Type const& rhs) const {
        return as_tuple() != rhs.as_tuple();
    }

    // .. and same for other operators ..

private:
    auto as_tuple() const {
        return std::tie(a, b, c); // all the members
    }
};

我可以使用 std::tie()std::forward_as_tuple() 来实现 as_tuple(),这两者有区别吗?我应该选择哪一个呢?


1
你是在问是否最好重构通用代码,以便你可以只调用一个函数而不是在多个地方复制相同的代码吗?是的。 - Barry
@Barry 可能我在询问 std::tie 和 std::forward_as_tuple 之间的区别。 - Alexey Starinsky
4
你的意思是什么,“可能”是什么意思?如果问题是“tieforward_as_tuple之间的区别是什么?”,你能不能把这个作为问题? - Barry
@Barry 是的。目前我已经在我的代码中使用std::tie()替换了std::forward_as_tuple(),但我还不确定是否完全正确。 - Alexey Starinsky
这个使用了std::tie()函数的代码能够编译吗?由于方法是const,但是tie会生成左值引用。 - Slava
显示剩余4条评论
2个回答

10

让我们先看一下函数签名。 std::tie() 的函数签名如下:

template< class... Types >
constexpr tuple<Types&...> tie( Types&... args ) noexcept;

相比之下,std::forward_as_tuple() 是:

template< class... Types >
constexpr tuple<Types&&...> forward_as_tuple( Types&&... args ) noexcept;
唯一的区别在于前者只接受左值,而后者接受左值和右值。如果所有的输入都是左值,就像在您的用例中一样,它们是完全等价的。
`std::tie()` 主要用于赋值的左侧(例如 `std::tie(a, b) = foo;` 来解包一个 `pair`),而 `std::forward_as_tuple()` 主要用于在函数中传递参数以避免复制。但它们都可以用来解决这个问题。`tie` 显然要短得多,而且可能更为人所知(cppreference 的 `tie` 示例使用它来实现 `operator<`),因此我会选择它。

1
@Slava 我们正在执行类似于 tie(a, b, c) 的操作,其中这些成员名称都是左值。 - Barry
4
它仍然是一个左值...只不过是 const。这些概念是相互独立的。 - Barry
5
@Slava lvalue在20世纪70年代进入C语言时,其含义“赋值左侧”就已经停止使用了。 - Cubbi
1
@Cubbi 他们应该同时停止使用“lvalue”这个术语。 - Slava
4
如果有帮助的话,可以将它们看作是“可爱的价值观”和“海盗价值观”。 - Yakk - Adam Nevraumont
显示剩余3条评论

3

这里有一篇关于同一主题的不错文章。

来自链接中的文章:

总之,当您需要构建一个元组时,请使用:

  1. 如果您需要返回元组中的值,请使用std::make_tuple
  2. 如果您需要返回元组中的左值引用,请使用std::tie
  3. 如果您需要保留输入的引用类型来构建元组,请使用std::forward_as_tuple

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接