Я обнаружил, что lvalue
лямбда-замыкания всегда можно передать в качестве rvalue
параметров функции.
Смотрите следующую простую демонстрацию.
#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;
}
Случай 2 является стандартным поведением (я просто использовал std::function
для демонстрационных целей, но любой другой тип будет вести себя так же).
Как и почему работает первый случай? Каково состояние fn1
закрытия после возврата функции?
fn1
неявно преобразуетсяstd::function
вfoo(fn1)
. Эта временная функция тогда является значением.std::function
быть выведены из лямбды?». Ваша программа не пытается вывести аргументы шаблонаstd::function
, поэтому нет проблем с неявным преобразованием.std::function
имеет неявный конструктор, который принимает лямбда-замыкания, поэтому существует неявное преобразование. Но в обстоятельствах связанного вопроса, создание шаблонаstd::function
не может быть выведено из лямбда-типа. (Например ,std::function<void()>
можно построить из[](){return 5;}
даже если она имеет непустой тип возвращаемого значения .Ответы:
Вызов
foo
требует, чтобы экземплярstd::function<void()>
этого привязывался к rvalue-ссылке .std::function<void()>
может быть построен из любого вызываемого объекта, который совместим сvoid()
подписью.Во-первых, временный
std::function<void()>
объект построен из[]{}
. Конструктор используется # 5 здесь , который копирует замыкание вstd::function
случае:Затем временный
function
экземпляр привязывается к ссылке rvalue.То же, что и раньше, потому что он был скопирован в
std::function
экземпляр. Первоначальное закрытие не затрагивается.источник
Лямбда это не а
std::function
. Ссылка не привязана напрямую .Случай 1 работает, потому что лямбда-символы можно преобразовать в
std::function
s. Это означает, что временныйstd::function
материал материализуется путем копированияfn1
. Указанный временный объект может быть привязан к rvalue-ссылке, поэтому аргумент соответствует параметру.И копирование также является причиной того,
fn1
что на нее ничего не влияетfoo
.источник
fn1
без гражданства, так как он ничего не захватывает.Это работает, потому что аргумент имеет тип, отличный от типа, на который ссылается rvalue. Из-за наличия другого типа рассматриваются неявные преобразования. Поскольку лямбда может вызываться для аргументов этого
std::function
, она неявно преобразуется в нее через конструктор преобразования шаблонов изstd::function
. Результатом преобразования является prvalue, и, таким образом, его можно связать со ссылкой на rvalue.источник