c++ - Os valores de fechamento lambda podem ser passados como parâmetros de referência rvalue




closures c++14 (2)

Descobri que os fechamentos lvalue lambda sempre podem ser passados ​​como parâmetros de função rvalue .

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 (eu apenas usei uma 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 do fechamento do fn1 após o retorno da função?


Como e por que o caso 1 funciona?

A chamada foo requer uma instância de std::function<void()> que se liga 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 a assinatura void() .

Primeiramente, um objeto temporário std::function<void()> é construído a partir de []{} . O construtor usado é o número 5 here , que copia o fechamento na instância std::function :

template< class F >
function( F f );

Inicializa o destino com std::move(f) . Se f for um ponteiro nulo para funcionar ou ponteiro nulo para membro, *this ficará vazio após a chamada.

Em seguida, a instância da function temporária é vinculada à referência rvalue.

Qual é o estado do fechamento do fn1 após o retorno da função?

O mesmo que antes, porque foi copiado em uma instância std::function . O fechamento original não é afetado.


Qual é o estado do fechamento do fn1 após o retorno da função?

fn1 é sem estado, pois não captura nada.

Como e por que o caso 1 funciona?

Funciona porque o argumento é de tipo diferente do tipo referenciado por rvalue. Por ter um tipo diferente, as conversões implícitas são consideradas. Como o lambda é Callable para os argumentos dessa std::function , é implicitamente conversível para ele através do construtor de conversão de modelos da std::function . O resultado da conversão é um pré-valor e, portanto, pode ser associado à referência de rvalue.







rvalue-reference