सी ++ में, उपयोगकर्ता परिभाषित इनपुट के बराबर गहराई (आयाम) का नेस्टेड वेक्टर उत्पन्न करना संभव है? उदाहरण के लिए, यदि कोई उपयोगकर्ता मान 2 का पूर्णांक इनपुट करता है, तो उसका प्रोग्राम vector< vector< vector<int> > > प्रकार का ऑब्जेक्ट बना सकता है। जाहिर है, सी ++ में समान व्यवहार को आसानी से प्राप्त करने के कई अन्य तरीके हैं, लेकिन मुझे पूरी तरह से दिलचस्पी है कि मनमाने ढंग से नेस्टेड वेक्टर की वास्तविक पीढ़ी संभव है या नहीं। प्रारंभ में, मैंने सोचा था कि यह अपेक्षाकृत छोटा होगा, लेकिन मेरे कार्यान्वयन सभी उत्सुक तरीकों से विफल रहे।

#include<iostream>
#include<vector>

using namespace std;

template<typename A> void vec_print(vector<A> in){
    cout << "{";
    for(typename vector<A> :: iterator i = in.begin(); i != in.end(); ++i){
        cout << *i << ", ";
    }
    cout << "}" << endl;
}

template<typename B> void vec_print(vector< vector<B> > in){
    cout << "{";
    for(typename vector< vector<B> > :: iterator i = in.begin(); i != in.end(); ++i){
        vec_print(*i); cout << ", ";
    }
    cout << "}" << endl;
}

template<typename T> auto generate(unsigned int d){
    if(d == 0){
        vector<T> in;
        return in;
    }
    return generate< vector<T> >(d - 1);
}

int main(){
    unsigned int d = 0;
    cin >> d;
    vec_print(generate<int>(d));
    return 0;
}

प्रारंभ में, मैंने सोचा था कि यह काम कर सकता है, हालांकि सी ++ कंपाइलर्स टेम्पलेट फ़ंक्शंस को कैसे संभालते हैं, इसकी मेरी समझ के कारण मुझे इसके बारे में संदेह था। क्रैश होने से पहले --std=c++11 ध्वज के साथ g++ कंपाइलर का उपयोग करते हुए, g++ कंपाइलर ने मुझे यह सूचित करते हुए त्रुटियों को बार-बार उगल दिया कि फ़ंक्शन रिटर्न टाइप डिडक्शन केवल C++17 विनिर्देश के तहत उपलब्ध था। इस प्रोग्राम को --std=c++17 ध्वज के साथ संकलित करने का प्रयास करने से कोई त्रुटि नहीं हुई, लेकिन संकलक बस दुर्घटनाग्रस्त हो गया। मुझे संदेह है कि संकलक ने अनंत संख्या में, या संभवतः 2 ^ 31, टेम्पलेट फ़ंक्शंस उत्पन्न करने का प्रयास किया, हालांकि मुझे उम्मीद है कि इसे अनंत टेम्पलेट फ़ंक्शन पीढ़ी की त्रुटि चेतावनी के साथ चुपचाप मरने के विरोध में संभाला होगा।

7
Connor McMonigle 6 नवम्बर 2017, 09:10

2 जवाब

सबसे बढ़िया उत्तर

मानक नेस्टेड टेम्पलेट इंस्टेंटेशन डेप्थ (1024) की एक सीमा निर्धारित करता है जो एक अनुरूप कार्यक्रम से अधिक नहीं होनी चाहिए। हालांकि इस सीमा या किसी अन्य कार्यान्वयन सीमा को लागू करने या निदान करने के लिए कार्यान्वयन की आवश्यकता नहीं है। यह किसी भी प्रोग्राम को संकलित करने में विफल हो सकता है जो "बहुत बड़ा" है।

जीसीसी और क्लैंग दोनों उपयोगकर्ता-परिभाषित सीमा को टेम्पलेट इंस्टेंटेशन गहराई पर सेट करने के लिए ध्वज का उपयोग कर सकते हैं। क्या हो रहा है यह देखने के लिए, उपयोग करें

g++ -std-c++17 -ftemplate-depth-20 yourprogram.cpp >& gcc.log

और देखें कि परिणामी लॉग फ़ाइल कितनी बड़ी है। फिर गहराई को बढ़ाकर 21 कर दें और इसे फिर से करें। इसे दो बार और करें, फिर अपने निष्कर्षों को -ftemplate-depth-1024 पर एक्सट्रपलेशन करें।

बेशक कंपाइलर क्रैशिंग एक क्यूओआई मुद्दा है और इसे एक बग माना जाना चाहिए। इसके बावजूद, आपका कार्यक्रम अनुरूप नहीं है क्योंकि यह एक कार्यान्वयन मात्रा से अधिक है।

यदि आप मनमाने ढंग से आयामों के वैक्टर को संभालना चाहते हैं, तो आप एक पुनरावर्ती टेम्पलेट का उपयोग नहीं कर सकते। आपको अन्य तकनीकों का सहारा लेना होगा जो संकलन समय के बजाय रन टाइम पर आयाम सेट करना चाहते हैं।

2
n. 'pronouns' m. 6 नवम्बर 2017, 13:47
struct element_t;

struct element_t {
  ~element_t() {}
  using element_p = std::shared_ptr<element_t>;
  using data_t = std::variant< std::vector<element_p>, int >;
  data_t data;
  element_t(element_t const&)=default;
  element_t(data_t in):data(std::move(in)) {}
  element_t()=default;
};

element_t::data_t generate( unsigned int x ) {
  if (x==0) return {unsigned{0}};
  auto ptr = std::make_shared<element_t>(generate(x-1));
  auto vec = std::vector<element_t::element_p>{ptr};
  element_t::data_t r(vec);
  return r;
}

परीक्षण कोड:

void print( element_t::data_t const& in ) {
    std::visit(
        [](auto const& e)
        {
            if constexpr( std::is_same< decltype(e), int const& >{} ) {
                std::cout << e << "\n";
            } else {
                for (const auto& x:e) {
                    if (!x)
                    {
                        std::cout << "null\n";
                    }
                    else
                    {
                        std::cout << "nest\n";
                        print(x->data);
                        std::cout << "unnest\n";
                    }
                }
            }
        },
        in
    );
}
int main() {
    auto r = generate(10);
    print(r);
}

लाइव उदाहरण

2
Yakk - Adam Nevraumont 6 नवम्बर 2017, 16:32