Подтвердить что ты не робот

Существует ли reference_wrapper <> для ссылок rvalue?

Интересно, как можно сделать следующее:

void f(string &&s) { 
  std::string i(move(s)); 
  /* other stuff */ 
} 

int main() { 
  std::string s; 
  bind(f, s)(); // Error.
  bind(f, move(s))(); // Error.
  bind(f, ref(s))(); // Error.
}

Как передать ссылку rvalue и сохранить ее как ссылку rvalue (возможно, завернутую) в оболочку вызова? Я знаю, что могу вручную написать класс типа std::reference_wrapper<>, который имеет функцию преобразования для T&&, но я бы предпочел избежать этого и использовать стандартную технологию.


Я реализовал его, как рекомендует AProgrammer:

template<typename T> struct adv { 
  T t; 
  explicit adv(T &&t):t(forward<T>(t)) {} 
  template<typename ...U> T &&operator()(U &&...) { 
    return forward<T>(t); 
  } 
}; 

template<typename T> adv<T> make_adv(T &&t) { 
  return adv<T>{forward<T>(t)}; 
}

namespace std { 
  template<typename T> 
  struct is_bind_expression< adv<T> > : std::true_type {}; 
} 

Теперь я могу сказать

void f(string &&s) { 
  std::string i(move(s)); 
  /* other stuff */ 
} 

int main() { 
  std::string s; 
  bind(f, make_adv(move(s)))(); // Works!
}

Если мы передадим значение lvalue в make_adv, он пересылает его как lvalue, ссылаясь на входной аргумент, поэтому в этом случае он может быть заменен на std::ref.

4b9b3361

Ответ 1

Я принимаю это.

20.8.10.1.2/10 в N3225

Значения связанных аргументов v1, v2,..., vN и их соответствующих типов V1, V2,..., VN зависят от типов TiD, полученных от вызова привязки, и cv-квалификаторов cv оболочки вызова g as следующим образом:

  • Если TiD является reference_wrapper, аргументом является tid.get(), а его тип Vi - T &;
  • если значение is_bind_expression:: value равно true, аргумент равен tid (std:: forward (uj)...) и его тип Vi является result_of:: type;
  • если значение j is_placeholder:: value не равно нулю, аргумент std:: forward (uj) и его тип Vi равен Uj &;
  • в противном случае это значение равно tid, а его тип Vi - TiD cv &.

Таким образом, единственная возможность иметь ссылку rvalue состоит в том, чтобы иметь is_bind_expression<TiD>::value true или is_placeholder<TiD>::value не ноль. Вторая возможность имеет последствия, которые вы не хотите, и достижение желаемого результата с первым будет означать, что проблема, которую мы пытаемся решить, решена, если мы ограничимся стандартными предоставленными типами. Таким образом, единственная возможность - предоставить вашу собственную оболочку и специализацию для is_bind_expression<TiD> (что разрешено 20.8.10.1.1/1), поскольку я ее не вижу.

Ответ 2

Как передать ссылку rvalue и сохранить ее как ссылку rvalue в оболочке вызовов?

Проблема заключается в том, что такой объект функции связывания можно вызывать несколько раз. Если объект функции перенаправил связанный параметр как rvalue, это, очевидно, будет работать только один раз. Таким образом, это немного проблема безопасности.

Но в некоторых случаях такая переадресация именно то, что вы хотите. Вы можете использовать лямбда в качестве посредника:

bind([](string& s){f(move(s));},move(s));

В принципе, я придумал эту комбинацию bind + лямбда в качестве обходного пути для отсутствия "захвата движения".

Ответ 3

Вы можете использовать изменяемый лямбда-объект.

auto func = [=]() mutable {
    f(std::move(s));
};