C++ Acquisizione generalizzata


Esempio

C ++ 14

Lambda può catturare espressioni, piuttosto che semplici variabili. Ciò consente a lambda di memorizzare i tipi di spostamento:

auto p = std::make_unique<T>(...);

auto lamb = [p = std::move(p)]() //Overrides capture-by-value of `p`.
{
  p->SomeFunc();
};

Ciò sposta la variabile p esterna nella variabile di cattura lambda, anche chiamata p . lamb ora possiede la memoria allocata da make_unique . Poiché la chiusura contiene un tipo che non può essere copiato, ciò significa che l' lamb è esso stesso non copiabile. Ma può essere spostato:

auto lamb_copy = lamb; //Illegal
auto lamb_move = std::move(lamb); //legal.

Ora lamb_move possiede la memoria.


Nota che std::function<> richiede che i valori memorizzati siano copiabili. Puoi scrivere la tua std::function richiede solo lo spostamento , oppure puoi semplicemente inserire il lambda in un wrapper shared_ptr :

auto shared_lambda = [](auto&& f){
  return [spf = std::make_shared<std::decay_t<decltype(f)>>(decltype(f)(f))]
  (auto&&...args)->decltype(auto) {
    return (*spf)(decltype(args)(args)...);
  };
};
auto lamb_shared = shared_lambda(std::move(lamb_move));

prende il nostro lambda di sola mossa e carica il suo stato in un puntatore condiviso, quindi restituisce un lambda che può essere copiato e quindi memorizzato in una std::function o simile.


L'acquisizione generalizzata utilizza auto deduzione del tipo auto per il tipo di variabile. Dichiarerà queste acquisizioni come valori per impostazione predefinita, ma possono anche essere riferimenti:

int a = 0;

auto lamb = [&v = a](int add) //Note that `a` and `v` have different names
{
  v += add; //Modifies `a`
};

lamb(20); //`a` becomes 20.

Generalizzare l'acquisizione non ha bisogno di catturare una variabile esterna. Può catturare un'espressione arbitraria:

auto lamb = [p = std::make_unique<T>(...)]()
{
    p->SomeFunc();
}

Questo è utile per dare a lambda valori arbitrari che possono contenere e potenzialmente modificare, senza doverli dichiarare esternamente al lambda. Naturalmente, ciò è utile solo se non si intende accedere a tali variabili dopo che lambda ha completato il proprio lavoro.