C++ الاحالة الثلاثية لامدا




c++11 lambda (4)

بما أن 2 lambdas ( lambda1 و lambda2 ) نوعان مختلفان ، ?: لا يمكن استنتاج نوع الإرجاع لـ lambda من lambda1 و lambda2 . يحدث هذا لأن هؤلاء 2 غير قابلة للتحويل إلى بعضها البعض.

أي فكرة لماذا لا يتم تجميع المقتطف التالي؟ يشتكي من خطأ "خطأ: المعاملون؟: لديهم أنواع مختلفة"

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

تتم ترجمة lambda Indivual إلى فئات مختلفة بواسطة المحول البرمجي. تعريف lambda1 مكافئ:

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

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

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

لذلك ، يتم إنشاء نوعين مختلفين من قبل المترجم وبالتالي عدم توافق نوع auto lambda = condition ? lambda1 : lambda2; auto lambda = condition ? lambda1 : lambda2;

سوف تعمل التالية:

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

لتسليط الضوء على أن كلا lambdas مختلفان بالفعل ، يمكننا استخدام <typeinfo> من المكتبة القياسية ومشغل typeid . نظرًا لأن lambdas ليس أنواعًا متعددة الأشكال ، يضمن المعيار تقييم عامل التشغيل typeid في وقت الترجمة ، لذلك المثال التالي صحيح حتى إذا تم تعطيل RTTI.

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

ناتج البرنامج (مع GCC 8.3 ، انظر على Gobolt ):

Z4mainEUlRZ4mainE1TE_/7654536205164302515
Z4mainEUlRZ4mainE1TE0_/10614161759544824066

لا يمكن للمترجم تحديد نوع auto يجب أن يكون:

auto lambda = condition ? lambda1 : lambda2;

لأن كل لامدا لديها نوع مختلف وفريد ​​من نوعه.

إحدى الطرق التي ستعمل بها هي:

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

من الغريب ، إذا كانت اللمبات أقل التقاطًا ، يمكن استخدام خدعة المشغل + :

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

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

يعمل هذا ، لأن + سوف يحول lambda إلى مؤشر دالة ، ولكل من مؤشرات الوظيفة نفس النوع (شيء يشبه void (*)(int) ).

مع GCC و Clang (ولكن ليس مع MSVC) ، يمكن حذف + ، سيظل تحويل lambdas إلى مؤشرات دالة.





conditional-operator