【问题标题】:What is the difference between std::tie and std::make_tuple with std::ref arguments?带有 std::ref 参数的 std::tie 和 std::make_tuple 有什么区别?
【发布时间】:2025-12-23 01:40:07
【问题描述】:

写表达式有语义上的区别

std::tie( x, y, z )

还有下面的表达式?

std::make_tuple( std::ref(x), std::ref(y), std::ref(z) )

如果有,有什么区别?

顺便说一句,这个问题与What is the difference between assigning to std::tie and tuple of references? 的要求不同,因为引用元组不是通过std::ref 创建的,而是通过显式指定类型来创建的。

【问题讨论】:

    标签: c++ c++11 reference tuples


    【解决方案1】:

    这两个表达式之间几乎没有功能上的区别。 tie() 更短,而make_tuple() 更通用。


    根据 [tuple.creation],make_tuple 会:

    template<class... Types>
    constexpr tuple<VTypes...> make_tuple(Types&&... t);
    

    对于类型中的每个Ti,让Uidecay_t&lt;Ti&gt;。那么如果Ui 等于reference_wrapper&lt;X&gt;,则VTypes 中的每个ViX&amp;,否则ViUi

    因此std::make_tuple( std::ref(x), std::ref(y), std::ref(z) ) 产生std::tuple&lt;X&amp;, Y&amp;, Z&amp;&gt;

    另一方面,tie 会:

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

    返回: tuple&lt;Types&amp;...&gt;(t...)。当t 中的参数为ignore 时,将任何值赋给对应的元组元素均无效。

    因此,std::tie(x, y, z) 也会产生 std::tuple&lt;X&amp;, Y&amp;, Z&amp;&gt;


    edge case 中的一个除外。

    【讨论】:

      【解决方案2】:

      xyz 中的任何一个是 std::reference_wrapper 的特化时会有所不同。

      #include <tuple>
      #include <functional>
      
      void f(std::reference_wrapper<int> x, int y, int z)
      {
          std::tie(x,y,z); // type is std::tuple<std::reference_wrapper<int>&, int&, int&>
          std::make_tuple(std::ref(x),std::ref(y),std::ref(z)); // type is std::tuple<int&, int&, int&>
      }
      

      【讨论】: