Lambda kapatma değerleri, değer referans parametreleri olarak geçirilebilir


18

lvalueLambda kapaklarının her zaman rvaluefonksiyon parametresi olarak geçebileceğini buldum .

Aşağıdaki basit gösterilere bakın.

#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;
}

Durum 2 standart davranıştır (sadece std::functiongösteri amacıyla a kullandım , ancak başka herhangi bir tür aynı davranır).

Durum 1 nasıl ve neden çalışır? fn1İşlev döndükten sonra kapanma durumu nedir ?


5
Çünkü olduğunu tahmin fn1örtük bir dönüştürülür std::functionin foo(fn1). O zaman bu geçici işlev bir değerdir.
eike

@RichardCritten Gerçekten emin değildim, bu yüzden bir cevap göndermedim. Sanırım şimdi başka birine gerek yok.
eike

1
@eike np Sık sık aynı şekilde hissediyorum ve birçok cevap yup.
Richard Critten

2
@Sumudu Soruyu soran kişi sizi yanılttı çünkü ne sormaya çalıştıklarını bilmiyorlardı. Sormak istedikleri şey: "Neden std::functionbir lambdadan çıkarılan argümanları şablonlayamıyor ". Programınız şablon bağımsız değişkenlerini çıkarmaya çalışmaz std::function, bu nedenle örtük dönüştürme ile ilgili bir sorun yoktur.
eerorika

1
Bağladığınız sorunun başlığı biraz yanıltıcı. std::functionlambda kapatmalarını kabul eden açık olmayan bir kurucuya sahiptir, bu nedenle örtük dönüşüm vardır. Ancak bağlantılı soru koşullarında, şablonun örneklenmesi std::functionlambda türünden çıkarılamaz. (Örneğin std::function<void()>, [](){return 5;}boş olmayan bir dönüş türüne sahip olmasına rağmen inşa edilebilir .
eike

Yanıtlar:


8

Durum 1 nasıl ve neden çalışır?

Çağırma foo, bir değer referansınastd::function<void()> bağlanan bir örneğini gerektirir . imzayla uyumlu herhangi bir çağrılabilir nesneden yapılabilir .std::function<void()>void()

İlk olarak, geçici bir std::function<void()>nesneden yapılır []{}. Kullanılan yapıcı # 5'tir burada , içine kopyalar kapatma std::functionörneği:

template< class F >
function( F f );

Hedefi ile ilklendirir std::move(f). Eğer füyesine fonksiyon ya boş gösterici bir boş gösterici ise, *thisçağrıdan sonra boş olacaktır.

Daha sonra, geçici functionörnek rvalue referansına bağlanır.


İşlev döndükten sonra fn1'in kapanma durumu nedir?

Daha önce olduğu gibi, çünkü bir std::functionörneğe kopyalandı . Orijinal kapak etkilenmez.


8

Bir lambda bir değil std::function. Referans doğrudan bağlanmıyor .

Durum 1 çalışmaktadır çünkü lambdalar std::functions'ye dönüştürülebilir . Bu araçlar geçici olduğunu std::functionisimli tarafından hayata kopyalama fn1 . Sözü edilen geçici, bir değer referansına bağlanabilir ve bu nedenle bağımsız değişken parametreyle eşleşir.

Kopyalama da neden fn1olan herhangi bir şeyden tamamen etkilenmez foo.


5

İşlev döndükten sonra fn1'in kapanma durumu nedir?

fn1 vatansızdır, çünkü hiçbir şey yakalamaz.

Durum 1 nasıl ve neden çalışır?

Argüman başvurulan rvalue değerinden farklı tipte olduğu için çalışır. Farklı bir türe sahip olduğu için örtük dönüşümler dikkate alınır. Lambda bunun argümanları için Çağrılabilir std::functionolduğundan, şablon dönüştürme yapıcısı aracılığıyla dolaylı olarak ona dönüştürülebilir std::function. Dönüşümün sonucu bir ön değerdir ve bu nedenle değer referansına bağlanabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.