何时使用std :: ref是必要的?

rit*_*ter 24 c++ portability correctness c++11

考虑:

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

是否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 );
    }
  }
};
Run Code Online (Sandbox Code Playgroud)

Ker*_* SB 15

  • make_tuple(0, a)做一个tuple<int, A>.
  • make_tuple(0, ref(a))做一个tuple<int, reference_wrapper<A>>.
  • 你也可以说tuple<int, A&> t(0, a);一个你无法使用make_tuple或使用的元组std::tie.

  • 严格来说,`std :: make_tuple(ref(a))`会导致`std :: tuple <A const &>`,而不是`std :: tuple <std :: reference_wrapper <const A >>`.标准库中腐烂其参数的许多部分都是特殊的,可以"衰减"`std :: reference_wrapper <T>`到`T&`.它们可以被识别,因为它们通常用'std :: decay'来指定,即使`std :: decay`本身不进行那种转换(有点令人沮丧). (3认同)
  • @弗兰克:元组可以用任何人类可能的东西来构造。您只需要返回对局部变量的引用,即“ a”的局部副本。使用ref可以返回对原始函数参数的包装引用。 (2认同)

jua*_*nza 12

std::ref没有引用,所以在你的代码示例中它没有做你期望的.std::ref创建一个与引用类似的对象.例如,当您想要实例化仿函数并将其类似引用的版本传递给标准库算法时,它可能很有用.由于算法按值使用仿函数,因此您可以使用std::ref包装仿函数.


Sau*_*ahu 10

其中一个例子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;
}
Run Code Online (Sandbox Code Playgroud)

std::thread构造拷贝所提供的值,而不转换为预期的参数类型(其是参考类型在这种情况下,看到update()).因此,我们需要换行真正需要引用的论据std::ref.

  • std::thread t1(更新,数据);会编译好,但问题是它不会改变数据的值。 (5认同)
  • @MohammadRoohitavaf 它无法编译!变量“data”必须包装在 std::ref(data) 中才能生成传递给 t1 的右值。如果函数“update”中的参数“data”的类型为“const int&amp;”,那么你是对的。但是 std::thread 会在内部复制参数,并且实际上不引用传递的变量“data”。 (2认同)