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




c++11 lambda (4)

जावा में, जब मुझे कॉलबैक फ़ंक्शन की आवश्यकता होती है, तो मुझे एक अनाम कक्षा को कार्यान्वित करना होगा। अज्ञात वर्ग के अंदर, यदि वे 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;
    struct { 
        int& y;
        int operator()(int x) { return x + y; }
    } anon = { y };
}

इसके बाद आप इसका उपयोग कर सकते हैं:

#include <iostream>
...
std::cout << anon(10) << std::endl;

उम्मीद के अनुसार 110 प्रिंट करता है। दुर्भाग्यवश आपके पास इस विधि के साथ अज्ञात प्रकार का उत्तराधिकारी नहीं हो सकता है क्योंकि प्रारंभकर्ता-सूची रचनात्मक प्रकार किसी अन्य प्रकार से प्राप्त नहीं हो सकते हैं। यदि विरासत महत्वपूर्ण है तो आपको एंडी प्रोल द्वारा उल्लिखित कन्स्ट्रक्टर विधि का उपयोग करना चाहिए।


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

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...
    );

यदि आपकी 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;
}

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

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

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

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







anonymous-class