c ++ 0x: referansla parametre olarak bir lambda almanın uygun yolu


85

int->intReferans olarak bir lambda parametresi alan bir işlevi tanımlamanın doğru yolu nedir ?

void f(std::function< int(int) >& lambda);

veya

void f(auto& lambda);

Son biçimin yasal sözdizimi olduğundan emin değilim.

Lambda parametresini tanımlamanın başka yolları var mı?


10
Neden referans olarak lambdaya ihtiyacınız var? Şunu musunuz const&?
deft_code

Yanıtlar:


84

Bir autoparametreniz olamaz . Temelde iki seçeneğiniz var:

Seçenek 1: Gösterdiğiniz std::functiongibi kullanın .

Seçenek # 2: Bir şablon parametresi kullanın:

template<typename F>
void f(F &lambda) { /* ... */}

Seçenek # 2, bazı durumlarda, gömülü lambda işlevi nesnesi için potansiyel bir yığın tahsisini önleyebildiğinden daha verimli olabilir, ancak yalnızca fbir şablon işlevi olarak bir başlığa yerleştirilebilirse mümkündür . Ayrıca, herhangi bir şablonda olduğu gibi, derleme sürelerini ve I-cache ayak izini artırabilir. Lambda işlev nesnesi yeterince küçükse, std::functionnesnede satır içi olarak gösterilebileceğinden, bunun da etkisinin olmayabileceğini unutmayın .


1
Şablonlar ayrıca genel yerel olmayan koda sıçramaları ortadan kaldırarak I-önbellek ayak izini de iyileştirebilir (bu durumda, önce genel amaçlı std::functionsarmalayıcıya atlamak zorunda kalmadan lambda'nızı doğrudan çalıştırın )
jalf

5
Bu alıntı, "lambda işlev nesnesi yeterince küçükse, std::functionnesnede satır içi olarak gösterilebilir " yanıltıcıdır. Lambdalar her zaman satır içi olarak kullanılabilir (derleyici elbette yapmamayı seçebilir). std::functionuygulamalar genellikle yığın tahsislerinden kaçınmak için küçük nesne optimizasyonunu kullanır. Bir lambda'nın yeterince küçük bir yakalama listesi varsa std::function, yığın kullanılmadan depolanacaktır . Bunun dışında bir lambda'nın boyutunun gerçek bir anlamı yoktur.
deft_code

2
@bdonlan: Bu arada, neden orada &yer void f(F & lambda)?
Nawaz

2
@bdonlan: Ancak const, lambda üyelerinin (değerlere göre yakalama) değiştirilemeyeceğini varsayar. Kullanıcının istediği şey olmayabilir.
Nicol Bolas

2
@bdonlan Bir süredir, ancak const olmayan bir başvuru olarak geçmek, işlev çağrısında geçici bir lambda oluşturulmasına izin vermiyor. Burada bir r-değeri referansı en iyisidir.
zennehoy

46

Ben şu şekilde kullanırım template:

template<typename Functor>
void f(Functor functor)
{
   cout << functor(10) << endl;
}

int g(int x)
{
    return x * x;
}
int main() 
{
    auto lambda = [] (int x) { cout << x * 50 << endl; return x * 100; };
    f(lambda); //pass lambda
    f(g);      //pass function 
}

Çıktı:

500
1000
100

Demo: http://www.ideone.com/EayVq


13

7 yıl geçtiğini biliyorum, ama işte kimsenin bahsetmediği bir yol:

void foo(void (*f)(int)){
    std::cout<<"foo"<<std::endl;
    f(1); // calls lambda which takes an int and returns void
}
int main(){
    foo([](int a){std::cout<<"lambda "<<a<<std::endl;});
}

Hangi çıktılar:

foo
lambda 1

Şablonlara veya std :: function'a gerek yok


12
bu, yalnızca işlev işaretçilerine (yakalamasız lambdalar) dönüşebilen lambdalar ile sınırlıdır ve ayrıca std::functionşablon sürümünde bu sınırlama bulunmadığı halde tam imzayı ( durum için olduğu gibi) belirtmeyi gerektirir .
Andriy Tylychko

Bunun için çok teşekkür ederim!
Mike Lee

1

void f(auto& lambda);

Bu yakın. Aslında derlenecek olan şey:

#include <cassert>

/*constexpr optional*/ const auto f = [](auto &&lambda)
{
  lambda();
  lambda();
};

int main()
{
  int counter = 0;
  f([&]{ ++counter; });
  assert(counter == 2);
}
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.