Lambda C ++ üçlü ataması


11

Aşağıdaki snippet'in neden derlenmediğine dair bir fikriniz var mı? "Hata: operands?: Farklı türleri var" hatasıyla şikayet ediyor

  auto lambda1 = [&](T& arg) {
      ...
  };
  auto lambda2 = [&](T& arg) {
      ...
  };
  auto lambda = condition ? lambda1 : lambda2;

Yanıtlar:


11

Bireysel lambdalar derleyici tarafından farklı sınıflara çevrilir. Örneğin, lambda1'in tanımı şuna eşittir:

class SomeCompilerGeneratedTypeName {
public:
  SomeCompilerGeneratedTypeName(...) { // Capture all the required variables here
  }

  void operator()(T& arg) const {
    // ...
  }

private:
  // All the captured variables here ...
};

Bu nedenle, derleyici tarafından iki farklı tür oluşturulur; auto lambda = condition ? lambda1 : lambda2;

Aşağıdakiler işe yarar:

auto lambda = condition ? std::function<void(T&)>(lambda1) : std::function<void(T&)>(lambda2);

Her iki lambdanın gerçekten farklı türler olduğunu vurgulamak <typeinfo>için standart kütüphaneden ve typeidoperatörden kullanabiliriz. Lambdalar polimorfik tipler değildir, bu nedenle standart 'tipid' operatörünün derleme zamanında değerlendirilmesini garanti eder. Bu, RTTI devre dışı olsa bile aşağıdaki örneğin geçerli olduğunu gösterir:

#include <iostream>
#include <typeinfo>

int main()
{
    struct T {

    };

    auto lambda1 = [&](T& arg) {
        return;
    };

    auto lambda2 = [&](T& arg) {
      return;
    };

    std::cout << typeid(lambda1).name() << "/" << typeid(lambda1).hash_code() << std::endl;
    std::cout << typeid(lambda2).name() << "/" << typeid(lambda2).hash_code() << std::endl;

    return 0;
}

Programın çıktısı (GCC 8.3 ile, bkz. Gobolt ):

Z4mainEUlRZ4mainE1TE_/7654536205164302515
Z4mainEUlRZ4mainE1TE0_/10614161759544824066

Tam hata "hatası: işlenenler??: Farklı türlerde 'f (const std :: vektör <int> &, size_t, size_t) [T = imzasız karakter; size_t = uzun imzasız int] :: <lambda (imzasız karakter & )> 've' f (const std :: vektör <int> &, size_t, size_t) [ile T = unsigned char; size_t = long unsigned int] :: <lambda (unsigned char &)> '" her tür ve formatta aynı.
inek

1
@cow Lamda kendi içinde aynı imzayı taşıdığından, derleyici, uygulama ayrıntılarını gizlemek ve daha anlaşılır bir hata vermek için, aynı olan her iki lambdanın yerini ve imzasını verir. Ama sonunda, hala olarak yorumlanıyorlar SomeCompilerGeneratedTypeName1veSomeCompilerGeneratedTypeName2
Xatyrian

1
@cow cevabın başlangıcını vurgulayan bir örnek ekledim, ilginç bulabilirsiniz
Xatyrian

12

İlginçtir ki, lambdalar yakalamadan uzaksa, operatör +hilesi kullanılabilir:

auto lambda1 = [](int arg) { ... };
auto lambda2 = [](int arg) { ... };

auto lambda = condition ? +lambda1 : +lambda2; // This compiles!
lambda(2019); 

Bu çalışır, çünkü +lambda'yı bir işlev işaretçisine dönüştürür ve her iki işlev işaretçisi de aynı türe sahiptir (gibi bir şey void (*)(int)).

GCC ve Clang ile (ancak MSVC ile değil) +atlanabilir, lambdalar hala fonksiyon işaretçilerine dönüştürülecektir.


1
Bu görsel stüdyoda işe yaramaz. Bir lambda'nın farklı çağrılara dönüşmesine izin veren uzantıları bunu önler.
Guillaume Racicot

@GuillaumeRacicot, bu not için teşekkürler. Bu konuda daha fazla bilgi edinebileceğim bir bağlantı verebilir misiniz?
Evg


2
@GuillaumeRacicot Son MSVC sürümünde derlenmiş gibi görünüyor. godbolt.org/z/ZQLWxy
Brian

@Brian Oh! Bu harika bir haber. Şimdi bazı kodları değiştirmek zorundayım. Teşekkürler!
Guillaume Racicot

10

Derleyici ne tür autoolması gerektiğine karar veremez :

auto lambda = condition ? lambda1 : lambda2;

çünkü her lambda farklı ve benzersiz bir türe sahiptir.

Çalışmanın bir yolu:

auto lambda = [&](T& arg) {
     return (condition ? lambda1(arg) : lambda2(arg));
}

8

Derleme yapmaz, çünkü her lambda'nın benzersiz bir türü vardır, ortak bir türü yoktur ?:.

Bunları içine alabilirsin std::function<void(T&)>, ör.

auto lamba1 = [&](T& arg) {
  ...
};
auto lambda2 = [&](T& arg) {
  ...
};
auto lambda = condition ? std::function(lambda1) : lambda2; // C++17 class template deduction

8

2 lambdas (yana lambda1ve lambda2) 2 farklı türleri, ?:için mümkün değildir anlamak dönüş türü lambdaile ilgili lambda1ve lambda2. Bunun nedeni, bu 2'nin birbirine dönüştürülememesidir.

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.