C ++ 11'de “otomatik” ile çıkartıldığında lambda türü nedir?


142

Ben bir lambda türü bir işlev işaretçisi olduğunu bir algı vardı. Aşağıdaki testi yaptığımda, yanlış olduğunu gördüm ( demo ).

#define LAMBDA [] (int i) -> long { return 0; }
int main ()
{
  long (*pFptr)(int) = LAMBDA;  // ok
  auto pAuto = LAMBDA;  // ok
  assert(typeid(pFptr) == typeid(pAuto));  // assertion fails !
}

Yukarıdaki kodda herhangi bir nokta eksik mi? Değilse, anahtar kelime typeofile çıkarıldığında lambda ifadesi autonedir?


8
“Lambda tipi bir fonksiyon göstergesidir” - verimsiz olur ve lambdaların tüm noktasını kaçırır.
Konrad Rudolph

Yanıtlar:


145

Bir lambda ifadesinin tipi belirtilmemiş.

Ancak genellikle functors için sadece sözdizimsel şekerdir. Bir lambda doğrudan bir fonktöre çevrilir. İçindeki her şey []yapıcı parametrelerine ve functor nesnesinin üyelerine dönüştürülür ve içindeki parametreler ()functor'ların parametrelerine dönüştürülür operator().

Hiçbir değişkeni yakalamayan bir lambda ( []'in içindeki hiçbir şey ) bir işlev işaretçisine dönüştürülemez (derleyiciniz bu ise MSVC2010 bunu desteklemez, ancak bu dönüşüm standardın bir parçasıdır).

Ancak lambda'nın gerçek türü bir işlev işaretçisi değildir. Bazı belirtilmemiş işlev türü.


1
MSVC2010, işlev işaretçisine dönüştürmeyi desteklemez, ancak MSVC11 destekler. blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
KindDragon

18
+1, "functors için yalnızca sözdizimsel şeker". Bunu hatırlayarak çok fazla karışıklık önlenebilir.
Ben


107

Fonksiyon çağrısı operatörünü aşırı yükleyen benzersiz bir isimsiz yapıdır. Her lambda örneği yeni bir tip sunar.

Yakalamayan bir lambda özel durumunda, yapı ayrıca bir fonksiyon işaretçisine dolaylı bir dönüştürmeye sahiptir.


2
Güzel cevap. Benimkinden çok daha kesin. +1 :)
jalf

4
Teklik kısmı için +1, ilk başta çok şaşırtıcı ve dikkati hak ediyor.
Matthieu M.

Gerçekten önemli değil, ancak tür gerçekten adlandırılmamış mı, yoksa derleme zamanına kadar bir isim verilmiyor mu? IOW, derleyici karar verilmiş adını bulmak için RTTI kullanabilirsiniz?
Ben

3
@Ben, isimsiz ve C ++ dili ile ilgili olarak, "derleyicinin karar verdiği bir isim" diye bir şey yoktur. Sonucu type_info::name()uygulama tanımlıdır, bu nedenle her şeyi döndürebilir. Uygulamada, derleyici, bağlayıcı uğruna türü adlandıracaktır.
avakar

1
Bu soru sorulduğunda Son zamanlarda, ben genellikle lambda tip söyleyebiliriz sahip bir isim, derleyici bunu biliyor, sadece anlatılmaz bu.
Andre Kostur

24

[C++11: 5.1.2/3]: Tipi lambda ekspresyon (aynı zamanda kapatma nesne türü) , benzersiz, isimsiz kaynaşmama sınıf tipidir - adı kapalı tip , özellikleri aşağıda açıklanmıştır -. Bu sınıf türü toplu değildir (8.5.1). Kapatma türü, karşılık gelen lambda ifadesini içeren en küçük blok kapsamı, sınıf kapsamı veya ad alanı kapsamı içinde bildirilir . [..]

Madde, bu türün değişen özelliklerini listelemeye devam eder. İşte bazı önemli noktalar:

[C++11: 5.1.2/5]:Bir için kapalı tip lambda ifade ortak sahip inlineolan parametreleri ve dönüş türü tarif edilmektedir işlev çağrısı operatörü (13.5.4) , lambda-ifade sitesindeki parametre beyanı-madde ve arka-dönüş-tipi , sırasıyla. [..]

[C++11: 5.1.2/6]:Lambda yakalaması olmayan bir lambda ifadesi için kapatma türünün, kapatma türünün işlev çağrısı operatörü ile aynı parametreye ve dönüş türlerine sahip işlevlere işaret etmek için genel bir sanal olmayan açık olmayan const dönüştürme işlevi vardır. Bu dönüştürme işlevi tarafından döndürülen değer, çağrıldığında, kapatma türünün işlev çağrısı operatörünü çağırmakla aynı etkiye sahip bir işlevin adresi olmalıdır.

Bu son pasajın sonucu, bir dönüşüm kullandıysanız, atama LAMBDAyapabilmenizdir pFptr.


3
#include <iostream>
#include <typeinfo>

#define LAMBDA [] (int i)->long { return 0l; }
int main ()
{
  long (*pFptr)(int) = LAMBDA;  // ok
  auto pAuto = LAMBDA;  // ok

  std::cout<<typeid( *pAuto ).name() << std::endl;
  std::cout<<typeid( *pFptr ).name() << std::endl;

  std::cout<<typeid( pAuto ).name() << std::endl;
  std::cout<<typeid( pFptr ).name() << std::endl;
}

İşlev türleri gerçekten aynıdır, ancak lambda yeni bir tür (bir işlev elemanı gibi) sunar.


Ben tavsiye CXXABI unmangling yaklaşım Zaten bu rotayı gidiyoruz. Bunun yerine, genellikle __PRETTY_FUNCTION__olduğu gibi kullanıyorum template<class T> const char* pretty(T && t) { return __PRETTY_FUNCTION__; }ve kalabalıklaşmaya başlarsa ekstraı çıkarıyorum. Şablon değişiminde gösterilen adımları görmeyi tercih ederim. Eğer gelmediyse __PRETTY_FUNCTION__, orada vb MSVC, alternatifleri vardır, ancak sonuç her zaman CXXABI gereklidir aynı nedenle derleyici bağlıdır.
John P

1

Ayrıca lambda'nın işlev işaretçisine dönüştürülebilir olduğunu da not etmeliyiz. Ancak typeid <>, lambda'dan genel işlev işaretçisine değişmesi gereken üç boyutlu bir nesne döndürür. Bu yüzden <> typeid testi geçerli bir varsayım değildir. Genel olarak C ++ 11, tip spesifikasyonu hakkında endişelenmemizi istemez; belirli bir tip, hedef tipe dönüştürülebilirse önemli olan her şeydir.


Bu adil, ancak baskı türleri, türün dönüştürülebilir olduğu ancak diğer kısıtlamaları karşılamadığı durumları yakalamaktan bahsetmemek için doğru türe ulaşmak için uzun bir yol kat ediyor. (Mümkün olan her zaman her zaman "yeniden" kısıtlamalara doğru iterdim, ancak bunu yapmaya çalışan birinin geliştirme sırasında çalışmalarını göstermek için daha fazla nedeni vardır.)
John P

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.