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


11

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

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

जवाबों:


11

व्यक्तिगत लंबोदर को संकलक द्वारा विभिन्न वर्गों में अनुवादित किया जाता है। उदाहरण के लिए, 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 ? std::function<void(T&)>(lambda1) : std::function<void(T&)>(lambda2);

यह उजागर करने के लिए कि दोनों लंबदा वास्तव में अलग-अलग प्रकार के हैं, हम <typeinfo>मानक पुस्तकालय और 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

पूर्ण त्रुटि है "त्रुटि: ऑपरेंड टू ;: विभिन्न प्रकार के 'च (कास्ट एसटीडी :: वेक्टर <int> &, size_t, size_t) [टी = अहस्ताक्षरित चार के साथ; size_t = long अहस्ताक्षरित int] :: <lambda (अहस्ताक्षरित चार &) )> 'और' f (const std :: वेक्टर <int> &, size_t, size_t) [T के साथ [अहस्ताक्षरित char; size_t = long अहस्ताक्षरित int] :: <lambda (अहस्ताक्षरित char &)> "", जिसमें मैं देख रहा हूं; समान सभी प्रकार और प्रारूप।
गाय

1
@ जंक क्योंकि अपने आप में लैम्ब्डा का एक ही हस्ताक्षर होता है इसलिए कंपाइलर, इसके कार्यान्वयन के विवरण को छिपाने के लिए और अधिक समझने योग्य त्रुटि देने के लिए, आपको लैम्ब्डा के स्थान और हस्ताक्षर देता है जो समान हैं। लेकिन अंत में, उनकी व्याख्या अभी भी की जाती है SomeCompilerGeneratedTypeName1औरSomeCompilerGeneratedTypeName2
Xatyrian

1
@cow ने एक उदाहरण जोड़ा जो उत्तर की शुरुआत को उजागर करता है, आपको यह दिलचस्प लग सकता है
Xatyrian

12

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

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

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

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

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


1
हालांकि यह दृश्य स्टूडियो पर काम नहीं करेगा। उनका विस्तार जो एक लैम्ब्डा को अलग-अलग कॉलिंग कॉन्वेशन में बदलने की अनुमति देता है, उसे रोकता है।
गिलियूम रेसिको

@GuillaumeRacicot, इस नोट के लिए धन्यवाद। क्या आप कृपया एक लिंक दे सकते हैं जहां मैं इसके बारे में अधिक पढ़ सकता हूं?
Evg


2
@GuillaumeRacicot यह हाल के MSVC संस्करण पर संकलित लगता है। godbolt.org/z/ZQLWxy
ब्रायन

@ ब्रायन ओह! यह उत्कृष्ट समाचार है। अब मुझे कुछ कोड बदलने होंगे। धन्यवाद!
गिलौम रेसिको

10

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

auto lambda = condition ? lambda1 : lambda2;

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

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

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

8

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

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

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

8

चूंकि 2 लैम्ब्डा ( lambda1और lambda2) 2 अलग-अलग प्रकार हैं, इसलिए और से ?:रिटर्न प्रकार नहीं घटा सकते हैं । ऐसा इसलिए होता है क्योंकि ये 2 एक दूसरे के लिए परिवर्तनीय नहीं हैं।lambdalambda1lambda2

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.