C++ लैंबडा का टर्नरी असाइनमेंट




c++11 lambda (4)

किसी भी विचार क्यों निम्नलिखित स्निपेट संकलन नहीं करता है? यह एक त्रुटि के साथ शिकायत करता है "त्रुटि: ऑपरेंड ?: विभिन्न प्रकार हैं"

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

उत्सुकता से, यदि लंबोदर कैप्चर-कम हैं, तो ऑपरेटर + चाल को नियोजित किया जा सकता है:

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

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

यह काम करता है, क्योंकि + लैम्ब्डा को एक फ़ंक्शन पॉइंटर में बदल देगा, और दोनों फ़ंक्शन पॉइंटर्स का एक ही प्रकार ( void (*)(int) जैसा कुछ है)।

जीसीसी और क्लैंग (लेकिन एमएसवीसी के साथ नहीं) के साथ, + छोड़ा जा सकता है, लैम्बडा को अभी भी फ़ंक्शन पॉइंटर्स में परिवर्तित किया जाएगा।


कंपाइलर यह तय नहीं कर सकता है कि auto किस प्रकार का होना चाहिए:

auto lambda = condition ? lambda1 : lambda2;

चूंकि हर मेमने का एक अलग और अनोखा प्रकार होता है।

एक तरीका है कि काम करेंगे:

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

यह संकलित नहीं करता है क्योंकि प्रत्येक लंबोदर के पास एक अद्वितीय प्रकार है, इसके लिए एक सामान्य प्रकार नहीं है ?:

आप उन्हें std::function<void(T&)> , जैसे में लपेट सकते हैं

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

संकलक द्वारा अलग-अलग कक्षाओं में इंडिविजुअल लैम्ब्डा का अनुवाद किया जाता है। 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 ? lambda1 : lambda2;

निम्नलिखित काम करेगा:

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

यह उजागर करने के लिए कि दोनों <typeinfo> वास्तव में अलग-अलग प्रकार के हैं, हम मानक पुस्तकालय और typeid ऑपरेटर से <typeinfo> उपयोग कर सकते हैं। क्योंकि लैम्ब्डा typeid प्रकार नहीं हैं, इसलिए मानक गारंटी देता है कि typeid ऑपरेटर का संकलन-समय पर मूल्यांकन किया जाता है, इसलिए typeid अक्षम होने पर भी निम्न उदाहरण मान्य है।

#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




conditional-operator