Когда нужно использовать std:: ref?

Рассмотрим:

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 );
    }
  }
};

Ответ 1

  • 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.

Ответ 2

std::ref не делает ссылку, поэтому в вашем примере кода он не делает то, что вы ожидаете. std::ref создает объект, который ведет себя аналогично ссылке. Это может быть полезно, например, когда вы хотите создать экземпляр функтора и передать его ссылочную версию стандартного библиотечного алгоритма. Поскольку алгоритмы принимают функторы по значению, вы можете использовать std::ref для обертывания функтора.

Ответ 3

Один из примеров, где 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 копирует предоставленные значения как есть, без преобразования в ожидаемый тип аргумента (который в этом случае является ссылочным типом, см. update()). Поэтому нам нужно обернуть аргументы, которые действительно должны быть ссылками в std::ref.