C++ Lambda generico


Esempio

c ++ 14

Le funzioni Lambda possono assumere argomenti di tipo arbitrario. Ciò consente a un lambda di essere più generico:

auto twice = [](auto x){ return x+x; };

int i = twice(2); // i == 4
std::string s = twice("hello"); // s == "hellohello"

Questo è implementato in C ++ facendo in modo che l' operator() del tipo di chiusura operator() sovraccarichi una funzione modello. Il seguente tipo ha un comportamento equivalente alla chiusura lambda sopra:

struct _unique_lambda_type
{
  template<typename T>
  auto operator() (T x) const {return x + x;}
};

Non tutti i parametri in un lambda generico devono essere generici:

[](auto x, int y) {return x + y;}

Qui, x è dedotto in base al primo argomento di funzione, mentre y sarà sempre int .

I lambda generici possono prendere argomenti come riferimento, usando le solite regole per auto e & . Se un parametro generico è preso come auto&& , questo è un riferimento di inoltro all'argomento passato e non un riferimento di rvalue :

auto lamb1 = [](int &&x) {return x + 5;};
auto lamb2 = [](auto &&x) {return x + 5;};
int x = 10;
lamb1(x); // Illegal; must use `std::move(x)` for `int&&` parameters.
lamb2(x); // Legal; the type of `x` is deduced as `int&`.

Le funzioni Lambda possono essere variadiche e inoltrare perfettamente i loro argomenti:

auto lam = [](auto&&... args){return f(std::forward<decltype(args)>(args)...);};

o:

auto lam = [](auto&&... args){return f(decltype(args)(args)...);};

che funziona solo "correttamente" con variabili di tipo auto&& .

Un motivo valido per utilizzare lambda generico è per la sintassi in visita.

boost::variant<int, double> value;
apply_visitor(value, [&](auto&& e){
  std::cout << e;
});

Qui stiamo visitando in modo polimorfico; ma in altri contesti, i nomi del tipo che stiamo passando non sono interessanti:

mutex_wrapped<std::ostream&> os = std::cout;
os.write([&](auto&& os){
  os << "hello world\n";
});

Ripetendo il tipo di std::ostream& is noise qui; sarebbe come dover menzionare il tipo di variabile ogni volta che la usi. Qui stiamo creando un visitatore, ma non uno polimorfico; auto è usato per lo stesso motivo per cui si può usare auto in un ciclo for(:) .