मुझे लगता है कि क्लैंग वास्तव में सही हो सकता है।
[Lambda.capture] / 11 के अनुसार , लैम्ब्डा में उपयोग की जाने वाली एक आईडी-अभिव्यक्ति का अर्थ है लैम्बडा की उप-कॉपी-कैप्चर की गई सदस्य केवल अगर यह ओड-उपयोग का गठन करती है । यदि ऐसा नहीं होता है, तो यह मूल इकाई को संदर्भित करता है । यह C ++ 11 के बाद से सभी C ++ संस्करणों पर लागू होता है।
C ++ 17 के अनुसार [basic.dev.odr] / 3 एक संदर्भ चर का उपयोग नहीं किया जाता है, अगर इसे करने के लिए lvalue-to-rvalue रूपांतरण लागू होता है, जो निरंतर अभिव्यक्ति देता है।
C ++ 20 ड्राफ्ट में हालांकि लैवल्यू-टू-रैवल्यू रूपांतरण की आवश्यकता समाप्त हो गई है और रूपांतरण को शामिल करने या न करने के लिए संबंधित मार्ग कई बार बदल गया। देखें राष्ट्रमंडल खेलों मुद्दा 1472 और राष्ट्रमंडल खेलों मुद्दा 1741 , साथ ही खुले राष्ट्रमंडल खेलों मुद्दा 2083 ।
चूंकि m
एक स्थिर अभिव्यक्ति (एक स्थिर भंडारण अवधि ऑब्जेक्ट का उल्लेख करते हुए) के साथ आरम्भ किया जाता है, इसका उपयोग करते हुए [expr.const] / 2.11.1 में प्रति अपवाद एक निरंतर अभिव्यक्ति प्राप्त करता है ।
हालांकि यह तब नहीं होता है जब लवलीन-टू-रिवल्यू रूपांतरण लागू होते हैं, क्योंकि n
एक स्थिर अभिव्यक्ति में मूल्य उपयोगी नहीं है।
इसलिए, इस पर निर्भर करता है कि ओवल्यू-टू-रेवल्यू रूपांतरणों को ओड-यूज़ का निर्धारण करने में लागू किया जाना है या नहीं, जब आप लैम्बडा में उपयोग करते हैं, तो m
यह लैम्ब्डा के सदस्य को संदर्भित कर सकता है या नहीं।
यदि रूपांतरण लागू किया जाना चाहिए, तो जीसीसी और एमएसवीसी सही हैं, अन्यथा क्लैंग है।
आप देख सकते हैं कि यदि आप m
एक निरंतर अभिव्यक्ति नहीं होने के प्रारंभ को बदलते हैं तो क्लैंग इसे व्यवहार में परिवर्तन करता है :
#include <stdio.h>
#include <functional>
int n = 100;
void g() {}
std::function<int()> f()
{
int &m = (g(), n);
return [m] () mutable -> int {
m += 123;
return m;
};
}
int main()
{
int x = n;
int y = f()();
int z = n;
printf("%d %d %d\n", x, y, z);
return 0;
}
इस मामले में सभी कंपाइलर सहमत हैं कि आउटपुट है
100 223 100
क्योंकि m
लैम्ब्डा में क्लोजर के सदस्य को संदर्भित किया जाएगा, जो कि int
टाइपिंग कॉपी-इन-रेफरेंस वेरिएबल m
इन से है f
।