Descobri que os lvalue
fechamentos lambda sempre podem ser passados como rvalue
parâmetros de função.
Veja a seguinte demonstração simples.
#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;
}
O caso 2 é o comportamento padrão (usei apenas um std::function
para fins de demonstração, mas qualquer outro tipo se comportaria da mesma maneira).
Como e por que o caso 1 funciona? Qual é o estado de fn1
fechamento após o retorno da função?
fn1
é implicitamente convertido em umstd::function
infoo(fn1)
. Essa função temporária é então um rvalue.std::function
ser deduzidos de um lambda". Seu programa não tenta deduzir os argumentos do modelostd::function
, portanto, não há problema com a conversão implícita.std::function
possui um construtor não explícito que aceita fechamentos lambda, portanto, há conversão implícita. Mas nas circunstâncias da questão vinculada, a instanciação de modelo destd::function
não pode ser inferida a partir do tipo lambda. (Por exemplo,std::function<void()>
pode ser construído a partir de[](){return 5;}
um tipo de retorno não nulo.Respostas:
A chamada
foo
requer uma instânciastd::function<void()>
que se ligue a uma referência rvalue .std::function<void()>
pode ser construído a partir de qualquer objeto que possa ser chamado que seja compatível com avoid()
assinatura.Em primeiro lugar,
std::function<void()>
é construído um objeto temporário[]{}
. O construtor usado é o número 5 aqui , que copia o fechamento nastd::function
instância:Em seguida, a
function
instância temporária é vinculada à referência rvalue.O mesmo de antes, porque foi copiado em uma
std::function
instância. O fechamento original não é afetado.fonte
Um lambda não é um
std::function
. A referência não liga diretamente .O caso 1 funciona porque as lambdas são conversíveis em
std::function
s. Isso significa que um temporáriostd::function
é materializado pela cópiafn1
. Esse temporário pode ser vinculado a uma referência rvalue e, portanto, o argumento corresponde ao parâmetro.E a cópia também
fn1
é por que não é afetada por nada que aconteçafoo
.fonte
fn1
é apátrida, pois não captura nada.Funciona porque o argumento é de tipo diferente do tipo que é referenciado por rvalue. Por ter um tipo diferente, as conversões implícitas são consideradas. Como o lambda é Callable para os argumentos disso
std::function
, é implicitamente convertível a ele através do construtor de conversão de modelo destd::function
. O resultado da conversão é um pré-valor e, portanto, pode ser associado à referência de rvalue.fonte