c++ क्या मैं सी++ में अनाम कक्षाएं बना सकता हूं और जावा में बाहरी चर को कैप्चर कर सकता हूं?




c++11 lambda (4)

यदि आपकी IA कक्षा में वास्तव में केवल एक वर्चुअल विधि है जिसे आपको ओवरराइड करने की आवश्यकता है (और वास्तविक जटिलता अन्य गैर-वर्चुअल विधियां हैं) लेकिन आप इस विधि को आवश्यक स्थानीय चर को कैप्चर नहीं करना चाहते हैं , इसके बारे में:

int main() {
  int y = 100;
  auto f = [=](int x){return x+y;};
  typedef decltype(f) F;
  struct IB : IA {
    F _f;
    IB(F _f): _f(_f) {}
    int f(int x) { return _f(x); }
  } a(f);
  doFancyWork(&a);
  return 0;
}

जावा में, जब मुझे कॉलबैक फ़ंक्शन की आवश्यकता होती है, तो मुझे एक अनाम कक्षा को कार्यान्वित करना होगा। अज्ञात वर्ग के अंदर, यदि वे final हैं तो मैं बाह्य चर का उपयोग कर सकता हूं।

अब मैं सी ++ में एक ही काम कर रहा हूं। मैं समझता हूं कि सी ++ लैम्ब्डा बेहतर काम करता है लेकिन कभी-कभी मुझे कई कार्यों में गुजरना पड़ता है जहां अज्ञात वर्गों के साथ, मुझे केवल एक उदाहरण में पास करने की आवश्यकता होती है।

मैंने निम्नलिखित उदाहरण की कोशिश की। यह जीसीसी 4.3.4 के साथ काम करता है।

class IA {
public:
  virtual int f(int x) = 0;  
};

int main() {
    class : public IA {
        int f(int x) { return x + 1; }
    } a;
    doFancyWork(&a);
    return 0;
}

क्या इस तरह के बाहरी चर को कैप्चर करना संभव है?

int main() {
    int y = 100; // mark y as final if possible
    class : public IA {
        int f(int x) { return x + y; }
    } a;
    return 0;
}

अद्यतन करें:

दूसरा उदाहरण संकलित नहीं होगा। त्रुटियां यहाँ हैं,

prog.cpp: In member function ‘virtual int main()::<anonymous class>::f(int)’:
prog.cpp:9: error: use of ‘auto’ variable from containing function
prog.cpp:7: error:   ‘int y’ declared here
prog.cpp: In function ‘int main()’:
prog.cpp:7: warning: unused variable ‘y’

अद्यतन करें:

मुझे बस ऐसा करने में कुछ और समस्याएं आईं:

  • मैं एक कन्स्ट्रक्टर नहीं लिख सकता क्योंकि कक्षा का नाम नहीं है
  • प्रारंभकर्ता सूची विरासत की अनुमति नहीं देता है।
  • इसे संकलित करने के लिए कोई भी परिवर्तन कोड को अपठनीय बनाता है।

मुझे लगता है मुझे अज्ञात वर्गों से दूर जाना है।


उन चरों को स्वचालित रूप से कैप्चर करने का कोई तरीका नहीं है, लेकिन आप वैकल्पिक दृष्टिकोण का उपयोग कर सकते हैं। यह है कि आप संदर्भ द्वारा कब्जा करना चाहते हैं:

int main() {
    int y = 100; // mark y as final if possible
    class IB : public IA {
    public:
      IB(int& y) : _y(y) {}
      int f(int x) { return x + _y; }
    private:
      int& _y;
    } a (y);
    return 0;
}

यदि आप मूल्य से कैप्चर करना चाहते हैं, तो बस int& int में बदलें।

वैसे भी, आप "मल्टी-कॉलबैक" ऑब्जेक्ट के रूप में लैम्बडास के टुपल का उपयोग करने पर विचार कर सकते हैं यदि यह आपको व्यक्तिगत लैम्ब्स के बारे में परेशान करता है। आपके पास अभी भी एक ऑब्जेक्ट में पैक की गई सबकुछ होगी और कैप्चरिंग मुफ्त में की जाएगी।

एक उदाहरण के रूप में:

auto callbacks = make_tuple(
    [] (int x) { cout << x << endl; },
    [&] () { cout << y << endl; }, // y is captured by reference
    [=] (int x) { cout << x + y << endl; }, // y is captured by value
    // other lambdas here, if you want...
    );

एक सी ++ लैम्ब्डा "बाहरी" चर को कैप्चर कर सकता है। [संपादित करें: जब मैंने पहली बार प्रश्न पढ़ा, तो मैंने किसी भी तरह से याद किया जहां उसने उल्लेख किया कि वह लैम्ब्स से अवगत है। बेहतर या बदतर के लिए, सी ++ में कुछ और नहीं है जो वास्तव में एक अज्ञात वर्ग जैसा दिखता है]।

उदाहरण के लिए:

#include <iostream>

int main(){ 

    int y = 100;
    auto lambda = [=](int x) { return x + y; };

    std::cout << lambda(2);
}

... अपने आउटपुट के रूप में 102 प्रिंट करता है।

ध्यान दें कि हालांकि यह कुछ हद तक एक समारोह की तरह दिखता है, एक सी ++ लैम्ब्डा वास्तव में कक्षा बनाने में परिणाम देता है। मुझे लगता है कि मुझे जोड़ना चाहिए: वह वर्ग तकनीकी रूप से अज्ञात नहीं है, लेकिन इसमें कुछ अनिर्दिष्ट नाम है जो कभी भी सीधे दिखाई नहीं देता है।

संपादित करें: हालांकि मैं अभी भी lambdas का उपयोग न करने के औचित्य के बारे में थोड़ा परेशान हूं। क्या एक वर्ग का उपयोग करने का इरादा है जिसमें कई सदस्य कार्य शामिल हैं? यदि ऐसा है, तो यह स्पष्ट नहीं है कि आप किस सदस्य को किस समय / किस उद्देश्य के लिए आमंत्रित करने के लिए निर्दिष्ट करते हैं। मेरी तत्काल प्रतिक्रिया यह है कि यह संदिग्ध रूप से लगता है जैसे आप किसी समस्याग्रस्त डिज़ाइन का समर्थन करने के लिए भाषा को मोड़ने की कोशिश कर रहे हैं।


यह कक्षा की गुमनाम नहीं है जो बाहरी चरों तक पहुंच प्रतिबंधित करता है। प्रश्न में, वाई सुलभ नहीं है क्योंकि वर्ग को एक समारोह में स्थानीय रूप से परिभाषित किया गया था।

स्थानीय स्तर पर परिभाषित वर्गों के लिए कुछ प्रतिबंध हैं। सबसे पहले, वे केवल स्थिर वैरिएबल तक पहुंच सकते हैं जो स्थिर हैं, लेकिन फ़ंक्शन के दायरे में उपलब्ध किसी भी अन्य चर का उपयोग कर सकते हैं। इसके अलावा, स्थानीय वर्गों में स्थिर डेटा सदस्य नहीं हो सकते हैं।

अनाम वर्गों के लिए, आपके पास रचनाकार और न ही विनाशक हो सकते हैं। सभी सदस्य कार्यों को वर्ग परिभाषा के अंदर घोषित किया जाना चाहिए। इसमें स्थैतिक स्थिर सदस्य नहीं हो सकते हैं, इसमें स्थिर स्थैतिक अभिन्न सदस्य शामिल हैं जिन्हें आम तौर पर कक्षा परिभाषा के अंदर तुरंत चालू किया जा सकता है। विरासत की अनुमति नहीं है।

बेनामी कक्षाएं सी ++ का एक अस्पष्ट कोने हैं और उनके पास थोड़ा व्यावहारिक मूल्य है। Lambda कार्यों और अन्य तकनीकें बहुत अधिक लचीला हैं। लेकिन कौन जानता है, शायद कुछ स्थितियों में यह कोड पठनीयता के साथ मदद कर सकता है।







anonymous-class