【问题标题】:When is the use of std::ref necessary?什么时候需要使用 std::ref ?
【发布时间】:2012-08-03 16:57:45
【问题描述】:

考虑:

std::tuple<int , const A&> func (const A& a) 
{
  return std::make_tuple( 0 , std::ref(a) );
}

编写正确且可移植的代码是否需要std::ref? (没有它也可以编译)

背景:

如果我删除 std::ref,我的代码构建良好,没有任何警告 (g++-4.6 -Wall),但无法正常运行。

如果感兴趣,A 的定义:

struct A {
  std::array<int,2> vec;
  typedef int type_t;

  template<typename... OPs,typename... VALs>
  A& operator=(const std::pair< std::tuple<VALs...> , std::tuple<OPs...> >& e) {
    for( int i = 0 ; i < vec.size() ; ++i ) {
      vec[i] = eval( extract(i,e.first) , e.second );
    }
  }
};

【问题讨论】:

标签: c++ c++11 portability correctness


【解决方案1】:

需要std::ref 的示例之一:

void update(int &data)  //expects a reference to int
{
    data = 15;
}
int main()
{
    int data = 10;

    // This doesn't compile as the data value is copied when its reference is expected.
    //std::thread t1(update, data);         

    std::thread t1(update, std::ref(data));  // works

    t1.join();
    return 0;
}

std::thread 构造函数复制提供的值,而不转换为预期的参数类型(在本例中为 reference 类型,请参阅update())。所以我们需要在std::ref包装真正需要引用的参数

【讨论】:

  • std::thread t1(更新,数据); will 编译得很好,但问题是它不会改变数据的值。
【解决方案2】:

std::ref 没有进行引用,因此在您的代码示例中它没有达到您的预期。 std::ref 创建一个行为类似于引用的对象。例如,当您想实例化一个仿函数并将其类似引用的版本传递给标准库算法时,它可能很有用。由于算法按值获取函子,因此您可以使用std::ref 来包装函子。

【讨论】:

    【解决方案3】:
    • make_tuple(0, a) 生成 tuple&lt;int, A&gt;
    • make_tuple(0, ref(a)) 生成 tuple&lt;int, reference_wrapper&lt;A&gt;&gt;
    • 你也可以说tuple&lt;int, A&amp;&gt; t(0, a); 来表示你不能用make_tuple 生成的元组,或者使用std::tie

    【讨论】:

    • 所以,如果ref 被删除,它应该会抛出一个错误。为什么不呢,知道吗?
    • @Frank:元组可以由任何人类可能的东西构成。你最终只返回一个对局部变量的引用,即a 的本地副本。使用ref,您可以返回对原始函数参数的包装引用。
    • @Frank:换句话说,你应该说return std::tuple&lt;int, A const &amp;&gt;(0, a);
    • 我明白了。但是,正如你所说,tuple&lt;int,A&gt; 被创建/返回。给定 tuple&lt;int,const A&amp;&gt; 作为返回类型,如何返回?
    • 严格来说std::make_tuple(ref(a)) 会产生std::tuple&lt;A const&amp;&gt;,而不是std::tuple&lt;std::reference_wrapper&lt;const A&gt;&gt;。衰减参数的标准库的许多部分都是特殊情况下“衰减”std::reference_wrapper&lt;T&gt;T&amp;。它们可以被识别,因为它们通常以 std::decay 的形式指定,即使 std::decay 本身不进行这种转换(有点令人沮丧)。
    【解决方案4】:

    回答标题中的问题 (When is the use of std::ref necessary?):std::ref 有用的另一种情况是循环遍历对象引用列表并修改它们:

    std::vector<int> v1, v2;
      
    void test() {
      for (std::vector<int>& vv : 
        // Compiles
        { std::ref(v1), std::ref(v2) } 
      
        // Compiler rejects this with:
        //   binding reference of type 'vector<...>' to value of 
        //   type 'const vector<...>' drops 'const' qualifier 
        // { v1, v2} 
      ) {
          vv.push_back(3);
      }
    }
    

    如果在列表中不使用std::ref,对象将被视为const,无法修改(另请参阅https://godbolt.org/z/Ta6YM31KM)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      • 2017-06-17
      • 2015-12-02
      • 2012-10-29
      相关资源
      最近更新 更多