typeof capture - Qual è il tipo di lambda quando dedotto con "auto" in C++11?





std::function expression (6)


[C++11: 5.1.2/3]: il tipo di espressione lambda (che è anche il tipo dell'oggetto di chiusura) è un tipo di classe non unione univoco, non denominato, chiamato tipo di chiusura , le cui proprietà sono descritto sotto. Questo tipo di classe non è un aggregato (8.5.1). Il tipo di chiusura è dichiarato nel più piccolo scope, scope della classe o scope del namespace che contiene la lambda-expression corrispondente. [..]

La clausola continua ad elencare le varie proprietà di questo tipo. Ecco alcuni punti salienti:

[C++11: 5.1.2/5]: il tipo di chiusura per un'espressione lambda ha un operatore di chiamata di funzione inline pubblica (13.5.4) i cui parametri e tipo di ritorno sono descritti dalla dichiarazione dei parametri dell'espressione lambda -clause e trailing-return-type rispettivamente. [..]

[C++11: 5.1.2/6]: Il tipo di chiusura per un'espressione lambda senza lambda-capture ha una funzione di conversione const non-public pubblica non-virtuale per puntare a una funzione che ha lo stesso parametro e tipi di ritorno come l'operatore di chiamata di funzione del tipo di chiusura. Il valore restituito da questa funzione di conversione deve essere l'indirizzo di una funzione che, invocata, ha lo stesso effetto del richiamo dell'operatore di chiamata di funzione del tipo di chiusura.

La conseguenza di questo passaggio finale è che, se si utilizzava una conversione, sarebbe possibile assegnare LAMBDA a pFptr .

Ho avuto la percezione che, il tipo di lambda è un puntatore a funzione. Quando ho eseguito il test successivo, ho trovato che fosse sbagliato ( demo ).

#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
  long (*pFptr)(int) = LAMBDA;  // ok
  auto pAuto = LAMBDA;  // ok
  assert(typeid(pFptr) == typeid(pAuto));  // assertion fails !
}

Il codice sopra manca qualsiasi punto? In caso contrario, qual è il typeof espressione lambda quando viene dedotta con auto parola chiave auto ?







È una struttura unnamed unica che sovraccarica l'operatore di chiamata di funzione. Ogni istanza di una lambda introduce un nuovo tipo.

Nel caso speciale di una lambda non catturante, la struttura in aggiunta ha una conversione implicita in un puntatore di funzione.




Il tipo di espressione lambda non è specificato.

Ma in genere sono solo zucchero sintattico per i funtori. Una lambda è tradotta direttamente in un funtore. Qualsiasi cosa all'interno di [] viene trasformata in parametri costruttore e membri dell'oggetto functor, ei parametri inside () vengono trasformati in parametri per l' operator() del functor operator() .

Un lambda che non cattura nessuna variabile (nulla all'interno di [] ) può essere convertito in un puntatore di funzione (MSVC2010 non supporta questo, se questo è il tuo compilatore, ma questa conversione è parte dello standard).

Ma il vero tipo di lambda non è un puntatore a funzione. È un tipo di functor non specificato.




Dovrebbe anche notare che lambda è convertibile in puntatore a funzione. Tuttavia, typeid <> restituisce un oggetto non trittico che dovrebbe differire da lambda al puntatore di funzione generico. Quindi il test per typeid <> non è un'ipotesi valida. In generale, C ++ 11 non vuole che ci preoccupiamo delle specifiche del tipo, tutto ciò che importa se un determinato tipo è convertibile in un tipo di destinazione.




Cos'è una funzione lambda?

Il concetto C ++ di una funzione lambda ha origine nel calcolo lambda e nella programmazione funzionale. Un lambda è una funzione senza nome che è utile (nella programmazione reale, non nella teoria) per brevi frammenti di codice che sono impossibili da riutilizzare e che non valgono la pena di nominarli.

In C ++ una funzione lambda è definita in questo modo

[]() { } // barebone lambda

o in tutta la sua gloria

[]() mutable -> T { } // T is the return type, still lacking throw()

[] è la lista di cattura, () la lista degli argomenti e {} il corpo della funzione.

La lista di cattura

La lista di cattura definisce cosa dall'esterno del lambda dovrebbe essere disponibile all'interno del corpo della funzione e come. Può essere o:

  1. un valore: [x]
  2. un riferimento [& x]
  3. qualsiasi variabile attualmente nell'ambito di riferimento per riferimento [&]
  4. uguale a 3, ma per valore [=]

Puoi mescolare uno dei precedenti in una lista separata da virgole [x, &y] .

La lista degli argomenti

L'elenco degli argomenti è lo stesso di qualsiasi altra funzione C ++.

Il corpo della funzione

Il codice che verrà eseguito quando viene chiamato effettivamente il lambda.

Restituzione del tipo di detrazione

Se un lambda ha solo un'istruzione return, il tipo restituito può essere omesso e ha il tipo implicito di decltype(return_statement) .

Mutevole

Se un lambda è contrassegnato come mutabile (es. []() mutable { } ) è permesso di mutare i valori che sono stati catturati dal valore.

Casi d'uso

La libreria definita dallo standard ISO trae enormi benefici da lambdas e aumenta l'usabilità di molte barre poiché ora gli utenti non devono ingombrare il loro codice con piccoli funtori in qualche ambito accessibile.

C ++ 14

In C ++ 14 i lambda sono stati ampliati con varie proposte.

Lambda Initialized Capture

Ora un elemento della lista di cattura può essere inizializzato con = . Ciò consente di rinominare le variabili e catturarle spostandosi. Un esempio tratto dallo standard:

int x = 4;
auto y = [&r = x, x = x+1]()->int {
            r += 2;
            return x+2;
         }();  // Updates ::x to 6, and initializes y to 7.

e uno estratto da Wikipedia che mostra come acquisire con std::move :

auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [ptr = std::move(ptr)] {return *ptr;};

Lambda generico

Lambdas ora può essere generico ( auto sarebbe equivalente a T qui se T era un argomento modello di tipo da qualche parte nel campo circostante):

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

Detrazione del tipo di ritorno migliorata

C ++ 14 consente tipi di ritorno dedotti per ogni funzione e non lo limita alle funzioni return expression; del modulo return expression; . Questo è anche esteso a lambda.





c++ lambda c++11 typeof auto