Genel lambda C ++ 14'te nasıl çalışır?


114

autoC ++ 14 standardında genel lambda nasıl çalışır ( argüman türü olarak anahtar kelime)?

Her farklı argüman türü için derleyicinin aynı gövdeye sahip yeni bir işlev oluşturduğu ancak türleri değiştirdiği (derleme zamanı polimorfizmi) veya Java'nın jeneriklerine (tür silme) daha çok benzeyen C ++ şablonlarına mı dayanıyor?

Kod örneği:

auto glambda = [](auto a) { return a; };

6
C ++ 14'e sabitlendi, başlangıçta söz konusu C ++ 11 kullanıldı
sasha.sochka

Yanıtlar:


130

Jenerik lambdalar tanıtıldı C++14.

Basitçe, lambda ifadesi tarafından tanımlanan kapatma türü, lambdas'ın normal, şablon olmayan çağrı operatörü yerine şablonlu bir çağrı operatörüne sahip olacaktır C++11(tabii ki, autoparametre listesinde en az bir kez göründüğünde).

Öyleyse örneğiniz:

auto glambda = [] (auto a) { return a; };

Yapacak glambdabu türünün bir örneği:

class /* unnamed */
{
public:
    template<typename T>
    T operator () (T a) const { return a; }
};

C ++ 14 Standart Taslağı n3690'ın 5.1.2 / 5 paragrafı, belirli bir lambda ifadesinin kapatma türünün çağrı operatörünün nasıl tanımlandığını belirtir:

Genel olmayan bir lambda ifadesi için kapanış türü, parametreleri ve dönüş türü sırasıyla lambda ifadesinin parametre bildirimi cümlesi ve sondaki dönüş türü tarafından açıklanan genel bir satır içi işlev çağrısı operatörüne (13.5.4) sahiptir. Genel bir lambda için, kapanış türü, şablon parametre listesi lambda'nın parametre bildirimi cümlesindeki her auto oluşumu için bir icat edilen tür şablon parametresinden oluşan genel bir satır içi işlev çağrısı işleci üye şablonuna (14.5.2) sahiptir, görünüm sırasına göre. İcat edilen tür şablon parametresi, karşılık gelen parametre bildirimi bir işlev parametre paketi (8.3.5) bildirirse bir parametre paketidir. İşlev çağrısı işleci şablonunun dönüş türü ve işlev parametreleri, lambda ifadesinin sondaki dönüş türünden ve parametre bildiriminden türetilir; bu, parametre bildirimi cümlesinin decl-belirticilerindeki her bir auto oluşumunu şu adla değiştirir: karşılık gelen icat edilmiş şablon parametresi.

En sonunda:

Her farklı argüman türü için derleyicinin aynı gövdeye sahip ancak değişen türlere sahip işlevler ürettiği şablonlara benzer mi yoksa Java'nın jeneriklerine daha mı benzer?

Yukarıdaki paragrafta açıklandığı gibi, jenerik lambdalar, şablonlu bir çağrı operatörüne sahip benzersiz, isimsiz işlevciler için sadece sözdizimsel şekerdir. Bu, sorunuzu cevaplamalıdır :)


7
Ancak, bir şablon yöntemiyle yerel olarak tanımlanmış bir sınıfa da izin verirler. Hangisi yeni.
Yakk - Adam Nevraumont

2
@Yakk: İşlev yerel şablonlarının kısıtlaması C ++ 11 ile tamamen kaldırılmamış mıydı?
Sebastian Mach

2
@phresnel: Hayır, bu kısıtlama kaldırılmadı
Andy Prowl

1
@AndyProwl: Hatamı anladım. Gerçekten kaldırılan şey, şablon argümanları olarak yerel türleri kullanmaktı (olduğu gibi int main () { struct X {}; std::vector<X> x; })
Sebastian Mach

1
@phresnel: Doğru, bu gerçekten değişti
Andy Prowl

25

Maalesef , C ++ 11'in ( http://ideone.com/NsqYuq ) parçası değiller :

auto glambda = [](auto a) { return a; };

int main() {}

G ++ 4.7 ile:

prog.cpp:1:24: error: parameter declared auto
...

Bununla birlikte , genel lambdalar için Portland önerisine göre C ++ 14'te uygulanma şekli :

[](const& x, & y){ return x + y; }

Bu, en büyük kısım için, anonim bir functor sınıfının olağan yaratılmasını sağlar, ancak türlerin olmaması durumunda, derleyici şablonlu bir üye yayınlar- operator():

struct anonymous
{
    template <typename T, typename U>
    auto operator()(T const& x, U& y) const -> decltype(x+y)
    { return x + y; }
};

Veya yeni teklife göre Genel (Polimorfik) Lambda İfadeleri Önerisi

auto L = [](const auto& x, auto& y){ return x + y; };

--->

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;

Yani evet, parametrelerin her permütasyonu için yeni bir örnekleme ortaya çıkacaktır, ancak bu functorun üyeleri yine de paylaşılacaktır (yani yakalanan argümanlar).


6
Tür belirleyicinin kaldırılmasına izin veren bu öneri , tamamen gülünç.
Orbit'te Hafiflik Yarışları

Onlar ile gitti 4.9 - g ++ . Tedarik etmeniz gerekiyor -std=c++1y.
emsr

İdeone'nin henüz gcc-4.9 ve C ++ 14'e sahip olmadığını bilmiyordum.
emsr

soru: bu autoklasik otomobil ile aynı kesinti kurallarına sahip mi? Şablon benzetmeye bakarsak, bu otomatikin otomatik olmadığı anlamına gelir, şablon türü kesintisi ile aynı kurallardır. O zaman soru şudur: şablon kesintisi ile eşdeğer automidir?
v.oddou

@ v.oddou: "Klasik otomobil" iyidir. Bana göre "klasik otomatik", "Yığın Değişkeni" anlamına gelir ve bir zamanlar staticveya tersi olarak kullanılmıştır register:) Her neyse, evet, burayı kullanmak autobaşlık altında normal bir şablon oluşturulduğu anlamına gelir. Aslında, bir lambda derleyicinin dahili olarak bir functor sınıfı ile değiştirilecektir ve bir autoparametre template <T> ... (T ...)bunun yayınlanacağı anlamına gelir .
Sebastian Mach

17

Şablonlara benzer (veya hatta eşdeğer) önerilen bir C ++ 14 özelliği (C ++ 11'de değil). Örneğin, N3559 şu örneği sağlar:

Örneğin, aşağıdaki ifadeyi içeren bu genel lambda ifadesi:

auto L = [](const auto& x, auto& y){ return x + y; };

aşağıdaki yapıya benzer şekilde davranan bir kapanış türünün ve nesnenin oluşturulmasıyla sonuçlanabilir:

struct /* anonymous */
{
    template <typename T, typename U>
    auto operator()(const T& x, U& y) const // N3386 Return type deduction
    { return x + y; }
} L;
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.