किसी ऐरे काम का आकार पाने के लिए यह टेम्प्लेट कोड कैसे करता है?


61

मुझे आश्चर्य है कि इस तरह के कोड को परीक्षण सरणी का आकार क्यों मिल सकता है? मैं टेम्पलेट में व्याकरण से परिचित नहीं हूं। शायद कोई कोड के अर्थ को समझा सकता है template<typename,size_t>। इसके अलावा, एक संदर्भ लिंक भी पसंद किया जाता है।

#define dimof(array) (sizeof(DimofSizeHelper(array)))
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];

void InitDynCalls()
{
    char test[20];
    size_t n = dimof(test);
    printf("%d", n);
}


क्या आपने C ++ 11 के बारे में n3337 जैसा कुछ पढ़ा ? यह आपके प्रश्न के लिए प्रासंगिक होना चाहिए! क्या आपने उपयोग करने पर विचार किया या ....std::arraystd::vector
बेसिल स्टायरनेविच

@BasileStarynkevitch मैंने वह नहीं पढ़ा है। कोड एक तृतीय-पक्ष लाइब्रेरी में दिखाई देता है। मैं सिर्फ इसका अर्थ निकालना चाहता हूं।
शैडो फ़ेंडेंड

एक उपयोगी अंतर्दृष्टि के लिए भी norvig.com/21-days.html देखें (और देखें कि उस पृष्ठ का लेखक कौन है)।
बेसिल स्टारीनेविच

2
का डुप्लिकेट की तरह लग रहा stackoverflow.com/questions/6106158/...
sharptooth

@BasileStarynkevitch मुझे उस लिंक की प्रासंगिकता समझ में नहीं आती है।
ऑर्बिट

जवाबों:


86

यह वास्तव में समझाने के लिए एक बहुत कठिन है, लेकिन मैं इसे जाने दूँगा ...

सबसे पहले, dimofआपको किसी सरणी में आयाम , या तत्वों की संख्या बताता है । (मेरा मानना ​​है कि विंडोज प्रोग्रामिंग वातावरण में "आयाम" पसंदीदा शब्दावली है)।

क्योंकि यह आवश्यक है C++और Cआप एक सरणी के आकार निर्धारित करने के लिए एक देशी रास्ता देना नहीं है।


अक्सर लोग मानते हैं sizeof(myArray)कि काम करेगा, लेकिन यह वास्तव में आपको तत्वों की संख्या के बजाय स्मृति में आकार देगा। प्रत्येक तत्व संभवतः 1 बाइट से अधिक मेमोरी लेता है!

अगला, वे कोशिश कर सकते हैं sizeof(myArray) / sizeof(myArray[0])। यह पहले तत्व के आकार से विभाजित सरणी की स्मृति में आकार देगा। यह ठीक है, और व्यापक रूप से Cकोड में उपयोग किया जाता है । इसके साथ प्रमुख समस्या यह है कि यह काम करने के लिए दिखाई देगा यदि आप एक सरणी के बजाय एक पॉइंटर पास करते हैं। मेमोरी में एक पॉइंटर का आकार आमतौर पर 4 या 8 बाइट्स होगा, भले ही वह जिस बिंदु को इंगित करता है वह तत्वों के अधिकतम का एक सरणी हो सकता है।


तो कोशिश करने के लिए अगली बात यह C++है कि किसी चीज को बल देने के लिए टेम्प्लेट का उपयोग करें जो केवल सरणियों के लिए काम करता है, और एक पॉइंटर पर एक कंपाइलर त्रुटि देगा। यह इस तरह दिख रहा है:

template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
    return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"

टेम्पलेट केवल एक सरणी के साथ काम करेगा। यह प्रकार को कम करेगा (वास्तव में आवश्यक नहीं है, लेकिन काम करने के लिए टेम्पलेट प्राप्त करने के लिए होना चाहिए) और सरणी का आकार, फिर यह आकार लौटाता है। जिस तरह से टेम्प्लेट लिखा गया है वह संभवतः एक पॉइंटर के साथ काम नहीं कर सकता है।

आमतौर पर आप यहां रुक सकते हैं, और यह C ++ स्टैंडर्ड लिबरी में है std::size


चेतावनी: यहाँ नीचे यह बालों वाली भाषा-वकील क्षेत्र में मिलती है।


यह बहुत अच्छा है, लेकिन अभी भी एक अस्पष्ट धार मामले में विफल रहता है:

struct Placeholder {
    static float x[8];
};

template <typename T, int N>
int ArraySize (T (&)[N])
{
    return N;
}

int main()
{
    return ArraySize(Placeholder::x);
}

ध्यान दें कि सरणी xहै की घोषणा की , लेकिन नहीं परिभाषित । इसके साथ एक फ़ंक्शन (यानी ArraySize) को कॉल करने के लिए , परिभाषित कियाx जाना चाहिए

In function `main':
SO.cpp:(.text+0x5): undefined reference to `Placeholder::x'
collect2: error: ld returned 1 exit status

आप इसे लिंक नहीं कर सकते।


आपके पास प्रश्न में मौजूद कोड एक तरीका है। वास्तव में किसी फ़ंक्शन को कॉल करने के बजाय, हम एक फ़ंक्शन की घोषणा करते हैं जो बिल्कुल सही आकार का ऑब्जेक्ट देता है । फिर हम sizeofउस पर ट्रिक का उपयोग करते हैं ।

ऐसा लगता है कि हम फ़ंक्शन को कॉल करते हैं, लेकिन sizeofविशुद्ध रूप से एक संकलन समय है, इसलिए फ़ंक्शन को वास्तव में कभी नहीं बुलाया जाता है।

template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
^^^^ ^                               ^^^
// a function that returns a reference to array of N chars - the size of this array in memory will be exactly N bytes

ध्यान दें कि आप वास्तव में किसी फ़ंक्शन से सरणी नहीं लौटा सकते हैं, लेकिन आप किसी सरणी में संदर्भ भेज सकते हैं।

फिर DimofSizeHelper(myArray)एक अभिव्यक्ति है जिसका प्रकारN char एस पर एक सरणी है । अभिव्यक्ति वास्तव में चलने योग्य नहीं है, लेकिन यह संकलन समय पर समझ में आता है।

इसलिए यदि आप वास्तव में फ़ंक्शन को कॉल करते हैं, तो आपको उस समय का आकारsizeof(DimofSizeHelper(myArray)) बताएगा जो आपको मिलेगा। हालांकि हम वास्तव में इसे नहीं कहते हैं।

ऑस्टिन पॉवर्स क्रॉस-आईड


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


3
@ शादोफेंडेंड यह भी गलत है। चीजें इससे भी खराब हैं, क्योंकि यह वास्तव में एक फ़ंक्शन की घोषणा नहीं है, यह एक फ़ंक्शन संदर्भ की घोषणा है ... मुझे अभी भी पता चल रहा है कि संभवतः कैसे समझा जाए।
BoBTFish

5
यह एक फ़ंक्शन संदर्भ की घोषणा क्यों है? "डिमोफ़साइज़ हेल्पर" से पहले "और" का अर्थ है कि बोल्ट का जवाब देने के लिए रिटर्न प्रकार चार (&) [एन] है।
शैडो फ़ेंडेंड

3
@ शडोवफेंड बिल्कुल सही। मैं सिर्फ बकवास कर रहा था क्योंकि मैंने अपना दिमाग गाँठ में बांध लिया था।
BoBTFish

किसी सरणी में आयाम तत्वों की संख्या नहीं है। अर्थात्, आपके पास 1, 2, 3 या उच्चतर आयाम वाले सरणियाँ हो सकती हैं, जिनमें से प्रत्येक में समान तत्वों की संख्या हो सकती है। जैसे array1D [1000], सरणी 2D [10] [100], array3D [10] [10] [10]। प्रत्येक में 1000 तत्व हैं।
jamesqf

1
@jamesqf C ++ जैसी भाषाओं में, एक बहुआयामी सरणी केवल एक सरणी होती है जिसमें अन्य सरणियाँ होती हैं। संकलक के दृष्टिकोण से, प्राथमिक सरणी में तत्वों की संख्या अक्सर इसकी सामग्री से पूरी तरह से असंबंधित होती है - जो माध्यमिक या तृतीयक सरणियां हो सकती हैं।
फेल्क्स

27
template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];

// see it like this:
//                char(&DimofSizeHelper(T(&array)[N]))[N];
// template name:       DimofSizeHelper
// param name:                             array
// param type:                          T(&     )[N])
// return type:   char(&                             )[N];

DimofSizeHelperएक टेम्पलेट फ़ंक्शन है जो एक T(&)[N]पैरामीटर लेता है - उर्फ ​​प्रकार के एन तत्वों के सी-सरणी के लिए एक संदर्भ और उर्फ ​​एन चार्ट की एक सरणी के लिए एक संदर्भ Tदेता है char (&)[N]। C ++ में एक char भेस में बाइट है और मानक द्वारा sizeof(char)होने की गारंटी है 1

size_t n = dimof(test);
// macro expansion:
size_t n = sizeof(DimofSizeHelper(array));

nको वापसी प्रकार का आकार सौंपा गया है DimofSizeHelper, जो sizeof(char[N])कि है N


यह थोड़ा जटिल है और अनावश्यक। यह करने का सामान्य तरीका था:

template <class T, size_t N>
/*constexpr*/ size_t sizeof_array(T (&)[N]) { return N; }

C ++ 17 के बाद से यह भी अनावश्यक है, जैसा कि हमारे पास है std::sizeजो ऐसा करता है, लेकिन अधिक सामान्य तरीके से, किसी भी stl-शैली कंटेनर का आकार प्राप्त करने में सक्षम होने के नाते।


जैसा कि BoBTFish द्वारा बताया गया है, यह एक किनारे के मामले के लिए आवश्यक है।


2
यह आवश्यक है यदि आप उस ODR का उपयोग नहीं कर सकते हैं जिसका आकार आप लेना चाहते हैं (यह घोषित है लेकिन परिभाषित नहीं है)। बेशक, बहुत अस्पष्ट है।
BoBTFish

टेम्पलेट फंक्शन में टाइप समझाने के लिए धन्यवाद। जो वास्तव में मदद करता है।
शैडो फ़ेंडेंड

3
हमारे पास std::extentC ++ 11 है जो संकलन समय है।
एलएफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.