2012-06-07 22 views
16

मैं एक श्रेणी से std::array कैसे शुरू कर सकता हूं (जैसा कि इटरेटर की एक जोड़ी द्वारा परिभाषित किया गया है)?एक श्रेणी (iterators की जोड़ी) के साथ std :: array प्रारंभ करें

कुछ इस तरह:

vector<T> v; 
... 
// I know v has exactly N elements (e.g. I just called v.resize(N)) 
// Now I want a initialized with those elements 
array<T, N> a(???); // what to put here? 

मैंने सोचा था कि array एक निर्माता, iterators की एक जोड़ी लेने के लिए इतना है कि मैं array<T, N> a(v.begin(), v.end()) कर सकता है के लिए होता है, लेकिन यह सब में कोई कंस्ट्रक्टर्स प्रतीत होता है!

मुझे पता है कि मैं copy सरणी में वेक्टर कर सकता हूं, लेकिन मैं डिफ़ॉल्ट रूप से पहले इसे बनाने के बिना सीधे वेक्टर सामग्री के साथ सरणी प्रारंभ करना चाहता हूं। मैं कैसे कर सकता हूँ?

+0

क्या वरीयता के लिए कोई कारण है? प्रदर्शन लगभग ठीक वही होगा क्योंकि डिफ़ॉल्ट कन्स्ट्रक्टर (आमतौर पर) केवल वही संरचना संरचना आवंटित करता है जो आपको वैसे भी चाहिए। कोई अतिरिक्त आवंटन, प्रतिलिपि या मुक्त नहीं होगा। –

+1

@ डेविडस्वार्टज़: शायद मेरे पास मेरी कक्षा में एक कॉन्स सरणी सदस्य है और इसलिए मुझे इसे निर्माता निकाय की बजाय प्रारंभकर्ता सूची में प्रारंभ करना होगा? – HighCommander4

+0

--- क्या हम खुद को यादृच्छिक एक्सेस इटरेटर्स तक सीमित कर सकते हैं? यदि हां, तो मेरे पास कुछ प्रकार का समाधान है --- कभी नहीं, संकलन समय पर * आकार * प्राप्त करने का कोई तरीका नहीं है। –

उत्तर

17
रैंडम एक्सेस iterators साथ

, और संकलन समय पर एक निश्चित आकार के बावजूद आपको ऐसा करने की एक pack of indices उपयोग कर सकते हैं:

template <std::size_t... Indices> 
struct indices { 
    using next = indices<Indices..., sizeof...(Indices)>; 
}; 
template <std::size_t N> 
struct build_indices { 
    using type = typename build_indices<N-1>::type::next; 
}; 
template <> 
struct build_indices<0> { 
    using type = indices<>; 
}; 
template <std::size_t N> 
using BuildIndices = typename build_indices<N>::type; 

template <typename Iterator> 
using ValueType = typename std::iterator_traits<Iterator>::value_type; 

// internal overload with indices tag 
template <std::size_t... I, typename RandomAccessIterator, 
      typename Array = std::array<ValueType<RandomAccessIterator>, sizeof...(I)>> 
Array make_array(RandomAccessIterator first, indices<I...>) { 
    return Array { { first[I]... } }; 
} 

// externally visible interface 
template <std::size_t N, typename RandomAccessIterator> 
std::array<ValueType<RandomAccessIterator>, N> 
make_array(RandomAccessIterator first, RandomAccessIterator last) { 
    // last is not relevant if we're assuming the size is N 
    // I'll assert it is correct anyway 
    assert(last - first == N); 
    return make_array(first, BuildIndices<N> {}); 
} 

// usage 
auto a = make_array<N>(v.begin(), v.end()); 

यह एक संकलक मध्यवर्ती प्रतियां eliding करने में सक्षम हो जाती है। मुझे लगता है कि धारणा एक बड़ा खिंचाव नहीं है।

असल में, यह इनपुट इटरेटर के साथ भी किया जा सकता है, क्योंकि ब्रेसिड-इनिट-सूची में प्रत्येक तत्व की गणना अगले तत्व (§8.5.4/4) की गणना से पहले अनुक्रमित होती है।

// internal overload with indices tag 
template <std::size_t... I, typename InputIterator, 
      typename Array = std::array<ValueType<InputIterator>, sizeof...(I)>> 
Array make_array(InputIterator first, indices<I...>) { 
    return Array { { (void(I), *first++)... } }; 
}  

*first++ चूंकि यह किसी भी I, हम एक डमी I जरूरत पैक विस्तार भड़काने के लिए नहीं है। void() के साथ प्रभाव की कमी के बारे में चेतावनियों को शांत करने और अधिभारित कॉमा को रोकने के लिए बचाव के लिए कॉमा ऑपरेटर।

+0

+1। अच्छा लगा। (लेकिन इस बार मुझे इस वाक्यविन्यास से नफरत है: 'टेम्पलेट <टाइपनाम >>>> 'मेरा मतलब डब्ल्यूटीएफ है।) – Nawaz

+0

स्पष्टीकरण के लिए,' बिल्ड इंडेक्स 'लिंक किए गए पृष्ठ पर' build_indices' टेम्पलेट है? क्या आप इसे उत्तर देने के लिए यहां शामिल कर सकते हैं? – ecatmur

+0

मेरा समाधान देखें जो बूस्ट का उपयोग करता है। – Nawaz

4

जैसा कि आपने देखा है, std :: सरणी में कोई कन्स्ट्रक्टर नहीं है (संकलक उत्पन्न डिफ़ॉल्ट कन्स्ट्रक्टर को छोड़कर)।

यह उद्देश्य पर किया गया था, इसलिए इसे एक सी सरणी की तरह स्थिर रूप से प्रारंभ किया जा सकता है। यदि आप एक स्थिर प्रारंभकर्ता के बिना सरणी भरना चाहते हैं, तो आपको अपना डेटा कॉपी करना होगा।

3

आप BOOST_PP_ENUM के रूप में उपयोग कर सकते हैं:

include <boost/preprocessor/repetition/enum.hpp> 

#define INIT(z, i, v) v[i] 

std::vector<int> v; 

//fill v with at least 5 items 

std::array<int,5> a = { BOOST_PP_ENUM(5, INIT, v) }; //MAGIC 

इधर, अंतिम पंक्ति के रूप में विस्तारित किया गया है:

std::array<int,5> a = {v[0], v[1], v[2], v[3], v[4]}; //EXPANDED LINE 

जो है तुम क्या चाहते।