I valori di chiusura lambda possono essere passati come parametri di riferimento del valore


18

Ho scoperto che lvaluele chiusure lambda possono sempre essere passate come rvalueparametri di funzione.

Vedi la seguente semplice dimostrazione.

#include <iostream>
#include <functional>

using namespace std;

void foo(std::function<void()>&& t)
{
}

int main()
{
    // Case 1: passing a `lvalue` closure
    auto fn1 = []{};
    foo(fn1);                          // works

    // Case 2: passing a `lvalue` function object
    std::function<void()> fn2 = []{};
    foo(fn2);                          // compile error

    return 0;
}

Il caso 2 è il comportamento standard (ho appena usato un std::functiona scopo dimostrativo, ma qualsiasi altro tipo si comporterebbe lo stesso).

Come e perché funziona il caso 1? Qual è lo stato di fn1chiusura dopo la restituzione della funzione?


5
Credo che sia perché fn1è implicitamente convertito in un std::functionin foo(fn1). Quella funzione temporanea quindi è un valore.
come il

@RichardCritten Non ero davvero sicuro, quindi non ho pubblicato una risposta. Penso che ora non sia necessario un altro.
come il

1
@eike np Mi sento spesso allo stesso modo, e molte risposte.
Richard Critten,

2
@Sumudu La persona che ha posto la domanda ti ha fuorviato perché non sapeva cosa stava cercando di porre. Ciò che intendevano chiedere era: "Perché non è std::functionpossibile dedurre argomenti di template da una lambda". Il programma non tenta di dedurre gli argomenti del modello di std::function, quindi non vi sono problemi con la conversione implicita.
Eerorika,

1
Il titolo della domanda che hai collegato è un po 'fuorviante. std::functionha un costruttore non esplicito che accetta le chiusure lambda, quindi esiste una conversione implicita. Ma nelle circostanze della domanda collegata, l'istanza del modello di std::functionnon può essere dedotta dal tipo lambda. (Ad esempio, std::function<void()>può essere costruito [](){return 5;}anche se ha un tipo di ritorno non vuoto.
Eike

Risposte:


8

Come e perché funziona il caso 1?

Il richiamo foorichiede un'istanza std::function<void()>che si lega a un riferimento di valore . std::function<void()>può essere costruito da qualsiasi oggetto richiamabile compatibile con la void()firma.

Innanzitutto, std::function<void()>viene costruito un oggetto temporaneo []{}. Il costruttore utilizzato è # 5 qui , che copia la chiusura std::functionnell'istanza:

template< class F >
function( F f );

Inizializza il target con std::move(f). Se fè un puntatore nullo da funzionare o un puntatore nullo al membro, *thissarà vuoto dopo la chiamata.

Quindi, l' functionistanza temporanea è associata al riferimento rvalue.


Qual è lo stato della chiusura di fn1 dopo la restituzione della funzione?

Come prima, perché è stato copiato in std::functionun'istanza. La chiusura originale non è interessata.


8

Una lambda non è una std::function. Il riferimento non si lega direttamente .

Il caso 1 funziona perché le lambda sono convertibili in std::functions. Ciò significa che un temporaneo std::functionsi materializza copiando fn1 . Detto temporaneo è in grado di essere associato a un riferimento al valore e quindi l'argomento corrisponde al parametro.

E la copia è anche il motivo per cui non fn1è completamente influenzato da qualsiasi cosa accada foo.


5

Qual è lo stato della chiusura di fn1 dopo la restituzione della funzione?

fn1 è apolide, poiché non cattura nulla.

Come e perché funziona il caso 1?

Funziona perché l'argomento è di tipo diverso rispetto al tipo a cui fa riferimento il valore. A causa del diverso tipo, vengono prese in considerazione le conversioni implicite. Poiché lambda è Callable per gli argomenti di questo std::function, è implicitamente convertibile in esso attraverso il costruttore di conversione di template di std::function. Il risultato della conversione è un valore e quindi può essere associato al riferimento al valore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.