2015-10-07 16 views
9

का पूर्ण प्रारंभिक क्रियान्वयन करने का कोई तरीका है, मैं std::array<size_t, N> (एन एक निश्चित टेम्पलेट-चर) का उपयोग कर रहा हूं।क्या std :: array

#include<array> 
template<size_t N> 
struct A{ 
    size_t function(std::array<size_t, N> arr){ return arr[N-1];} // just an example 
}; 

int main(){ 
    A<5> a; 
    a.function({{1,2,3,4,5}})); 
} 

और यह ठीक काम करता है। समस्या यह है कि यह अन्य कोड चुपचाप अनुमति दी है है:

A.function({{1,2,3}})); 

यही कारण है, यहां तक ​​कि याद तत्वों array किसी भी तरह आरंभ नहीं हो जाता के साथ, भले ही वह अच्छी तरह से परिभाषित किया गया है (शेष जैसे तत्वों शून्य करने के लिए प्रारंभ, मुझे यकीन है कि नहीं कर रहा हूँ) यह त्रुटियों का एक संभावित स्रोत है।

अतिरिक्त तत्वों के प्रारंभ को लागू करने का कोई तरीका है? ईजी। एक कंपाइलर त्रुटि या एक चेतावनी उत्पन्न करके।

एक विकल्प है कि मैं विचार initializer_list

size_t function2(std::initializer_list<size_t> il){ assert(il.size() == N); ...} 

उपयोग करने के लिए समस्या यह है कि यह सबसे अच्छा में एक रनटाइम त्रुटि और हर कॉल में एक चेक उत्पन्न है। मैं एक कंपाइलर त्रुटि/चेतावनी पसंद करेंगे।

मुझे std::array<>{} के डिफ़ॉल्ट प्रारंभिकरण से बहुत परेशान नहीं है, लेकिन अपूर्ण प्रारंभिकरण से बहुत परेशान नहीं है। (हो सकता है, के बाद से इस T[N] स्थिर सरणी के व्यवहार से प्राप्त होती है कुछ भी नहीं इसके बारे में क्या किया जा सकता है।)

मैं clang 3.5 और gcc 5 उपयोग करने की कोशिश।

+0

@texasbruce, धन्यवाद, मैंने कोशिश की। समस्या यह है कि 'st' :: array ' में 'एन' तर्क से कम से कम नहीं किया जा सकता है (कम से कम मेरे कंपाइलर में), और वहां से 'std :: enable_if' पर मदद नहीं करता है। या आप कुछ अलग मतलब है? – alfC

+0

मैंने आपके प्रश्न का गलत व्याख्या किया। enable_if यहां मदद नहीं करेगा – texasbruce

उत्तर

2

सरल उत्तर: आप नहीं कर सकते।

जब एक सूची के साथ std::array आरंभ, यह एक aggregate initialization कर रहा है, और यह here समझाया गया है जब सूची का आकार सदस्य की संख्या से कम है:

  • तो प्रारंभकर्ता खंड की संख्या से कम है सदस्यों या प्रारंभकर्ता सूची की संख्या पूरी तरह से खाली है, शेष सदस्यों को कक्षा परिभाषा में प्रदान किए जाने पर, और अन्यथा (सी ++ 14 के बाद) खाली सूचियों द्वारा उनके ब्रेस-या-बराबर प्रारंभकर्ताओं द्वारा प्रारंभ किया जाता है, जो मान-प्रारंभिकता करता है। यदि किसी संदर्भ प्रकार का सदस्य इन शेष सदस्यों में से एक है, तो कार्यक्रम खराब हो गया है (संदर्भ मूल्य-प्रारंभिक नहीं हो सकते हैं)

यह आकार सूची से कम प्रदान करने के लिए केवल एक कानूनी और स्वीकार्य व्यवहार है, तो संकलक कुछ भी शिकायत नहीं करेगा। आपका कोड:

A<5> a; 
a.function({{1,2,3,0,0}})); 

संकलक करने के लिए:

A<5> a; 
a.function({{1,2,3}})); 

बराबर है। आपकी सबसे अच्छी शर्त रनटाइम त्रुटि है (जो आपकी इच्छा के अनुसार नहीं हो सकती है)।

+0

मुझे लगता है कि रनटाइम चेक भी संभव नहीं है क्योंकि उदाहरण के लिए छोड़े गए शून्य से कोई वास्तविक शून्य कैसे अंतर कर सकता है। प्रारंभकर्ता सूची में बदलना एक अलग काम है। – alfC

+0

मैंने यह जवाब स्वीकार कर लिया क्योंकि यह औपचारिक रूप से सही है, अन्य उत्तरों अच्छे कामकाज हैं। – alfC

3

आप अपने वस्तुओं

template <class T> 
struct WrapT 
{ 
    WrapT() = delete; 

    WrapT(T e) : value(e){} 

    public: T value; 
    // or add some operator() 
}; 

और

size_t function(std::array<WrapT<size_t>, N> arr){ return arr[N-1].value;} 

के लिए एक आवरण बना सकते हैं जिससे की तरह (पूर्ण ब्रेस-init साथ)

function({ {{1}, {2}, {3}, {4}} }); 

एक समारोह कॉल क्योंकि संकलन नहीं होगा हटाए गए फ़ंक्शन का उपयोग करना। Live example। वाक्यविन्यास थोड़ा बेकार है, और फिर भी मुझे यकीन नहीं है कि सभी संभावित मूल्य-प्रारंभिक मामलों को कवर किया गया है।

@ डीपी अंक बताते हैं कि आप सबसे निचले लोगों को छोड़ सकते हैं, इसलिए आप अपना मूल कोड प्राप्त करें: function({{ 1, 2, 3, 4, 5 }})

+0

इससे मुझे समझ में आया कि समस्या न केवल 'std :: array' बल्कि तत्व प्रकार के भी है। यह उत्तर बहुत वैचारिक है क्योंकि यह मुझे बताता है कि मुझे शायद स्पष्ट रूप से इनटाइलाइज्ड प्रकार का उपयोग करना चाहिए। 'Clang' में मुझे किसी कारण से प्रत्येक तत्व के चारों ओर अतिरिक्त ब्रैकेट की आवश्यकता नहीं है। – alfC

+0

WrapT में स्वचालित रूपांतरण 'ऑपरेटर टी एंड()' और 'ऑपरेटर टी कॉन्स्ट एंड() const' हो सकता है। इसके अलावा मैं 'टेम्पलेट <क्लास टी, size_t N> को प्रारंभिक_एरेरे = std :: array , N>; का उपयोग करके परिभाषित कर सकता हूं, और इसे' ... function (itialized_array arr) {...} 'के रूप में उपयोग करें। – alfC

+2

आप ब्रेस-एलिशन का उपयोग कर सकते हैं, यह ओपी के '{{1, 2, 3, 4, 5}} 'वाक्यविन्यास को पुनर्स्थापित करता है। पहला '{' 'std :: array' प्रारंभ करता है, दूसरा दूसरा 'std :: array' की आंतरिक सी-शैली सरणी (एक्स) प्रारंभ करता है, फिर हमारे पास' 1' है जो '{' इतना नहीं है ब्रेस-एलिशन लागू होता है। (एक्स) के सदस्य, यानी 'WrapT ' तत्व प्रत्येक प्रारंभिक '1', '2' और इसी तरह से प्रारंभ किए गए हैं। यह काम करता है क्योंकि 'लपेटें (टी ई) 'निहित रूपांतरण की अनुमति देता है। – dyp

3

आप पैरामीटर पैक का उपयोग करके यह लागू कर सकते हैं, लेकिन थोड़ा अलग वाक्य रचना के साथ:

#include <array> 

template<size_t N> 
struct A{ 
    template<typename... T> 
    size_t function(T&&... nums) 
    { 
    static_assert(sizeof...(nums) == N, "Wrong number of arguments"); 
    std::array<size_t, N> arr = { std::forward<size_t>(nums)... }; 
    return arr[N-1]; 
    } 
}; 

int main(){ 
    A<5> a; 
    a.function(1,2,3,4,5); // OK 
    a.function(1,2,4,5); // Compile-time error 
} 

लेकिन, मुझे लगता है कि लागू करने के लिए है कि संकलन समय में कोई अच्छा तरीका है। मैं केवल प्रारंभिक सूची के आकार की जांच के लिए उत्पादन कोड में assert(il.size() == N) का उपयोग करूंगा।

संबंधित मुद्दे