هل يمكن لأي شخص أن يشرح رمز القالب هذا الذي يعطيني حجم المصفوفة؟[ينسخ]

StackOverflow https://stackoverflow.com/questions/437150

  •  22-07-2019
  •  | 
  •  

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

template<typename T, size_t n>
size_t array_size(const T (&)[n])
{
    return n;
}

الجزء الذي لم أحصل عليه هو المعلمات الخاصة بوظيفة القالب هذه.ماذا يحدث للمصفوفة عندما أمررها من هناك مما يعطي n كعدد العناصر في المصفوفة؟

هل كانت مفيدة؟

المحلول

حسنًا، عليك أولاً أن تفهم أن محاولة الحصول على قيمة من المصفوفة يمكن أن تعطيك مؤشرًا لعنصرها الأول:

int a[] = {1, 2, 3};
int *ap = a; // a pointer, size is lost
int (&ar)[3] = a; // a reference to the array, size is not lost

تشير المراجع إلى الكائنات باستخدام نوعها الدقيق أو نوع الفئة الأساسية الخاصة بها.المفتاح هو أن القالب يأخذ المصفوفات حسب المرجع.المصفوفات (وليست إشارات إليها) كمعلمات غير موجودة في C++.إذا قمت بإعطاء معلمة نوع مصفوفة، فسيكون مؤشرًا بدلاً من ذلك.لذا فإن استخدام المرجع ضروري عندما نريد معرفة حجم المصفوفة التي تم تمريرها.يتم استنتاج الحجم ونوع العنصر تلقائيًا، كما هو الحال عمومًا بالنسبة لقوالب الوظائف.القالب التالي

template<typename T, size_t n>
size_t array_size(const T (&)[n]) {
    return n;
}

تم الاتصال به باستخدام المصفوفة المحددة مسبقًا a سيتم ضمنيًا إنشاء الوظيفة التالية:

size_t array_size(const int (&)[3]) {
    return 3;
}

والتي يمكن استخدامها مثل هذا:

size_t size_of_a = array_size(a);

هناك اختلاف قمت بإنشائه منذ بعض الوقت [يحرر:تبين أن شخصًا ما كان لديه نفس الفكرة بالفعل هنا] والتي يمكن تحديد قيمة في وقت الترجمة.بدلاً من إرجاع القيمة مباشرةً، فإنه يمنح القالب نوع إرجاع يعتمد على ذلك n:

template<typename T, size_t n>
char (& array_size(const T (&)[n]) )[n];

أنت تقول إذا كان المصفوفة لديها n العناصر، فإن نوع الإرجاع هو إشارة إلى مصفوفة لها حجم n ونوع العنصر char.الآن، يمكنك الحصول على حجم محدد في وقت الترجمة للمصفوفة التي تم تمريرها:

size_t size_of_a = sizeof(array_size(a));

لأن مجموعة من char نأخذ n العناصر لها حجم n, ، سيعطيك هذا عدد العناصر في المصفوفة المحددة أيضًا.في وقت الترجمة، لذلك يمكنك القيام به

int havingSameSize[sizeof(array_size(a))];

نظرًا لأن الوظيفة لا يتم استدعاؤها فعليًا أبدًا، فهي لا تحتاج إلى تعريف، لذلك لا تحتوي على نص.آمل أن أتمكن من توضيح الأمر قليلاً.

نصائح أخرى

فكر في الأمر بهذه الطريقة، لنفترض أن لديك مجموعة من الوظائف:

// Note that you don't need to name the array, since you don't
// actually reference the parameter at all.
size_t array_size(const int (&)[1])
{
    return 1;
}

size_t array_size(const int (&)[2])
{
    return 2;
}

size_t array_size(const int (&)[3])
{
    return 3;
}
// etc...

الآن عندما تستدعي هذا، ما هي الوظيفة التي يتم استدعاؤها؟

int a[2];
array_size(a);  

الآن إذا قمت بنموذج حجم المصفوفة، فستحصل على:

template <int n>
size_t array_size(const int (&)[n])
{
    return n;
}

سيحاول المترجم إنشاء نسخة من array_size تتطابق مع أي معلمة تستدعيها بها.لذا، إذا قمت باستدعائها بمصفوفة مكونة من 10 ints، فسوف تقوم بإنشاء مثيل array_size بـ n=10.

بعد ذلك، ما عليك سوى إنشاء قالب للنوع، حتى تتمكن من استدعائه بأكثر من مجرد مصفوفات int:

template <typename T, int n>
size_t array_size(const T (&)[n])
{
    return n;
}

إنتهيت.

يحرر:ملاحظة حول (&)

هناك حاجة إلى الأقواس حول & للتمييز بين مجموعة من مراجع int (غير قانونية) والإشارة إلى مجموعة من ints (ما تريد).منذ أسبقية [] أعلى من &, ، إذا كان لديك التصريح:

const int &a[1];

بسبب أسبقية عامل التشغيل، ينتهي بك الأمر بمصفوفة مكونة من عنصر واحد من مراجع const إلى int.إذا كنت تريد & إذا تم تطبيقه أولاً، فأنت بحاجة إلى فرض ذلك باستخدام الأقواس:

const int (&a)[1];  

الآن لديك مرجع ثابت لمجموعة عناصر واحدة من ints.في قائمة معلمات الدالة، لا تحتاج إلى تحديد اسم المعلمة إذا كنت لا تستخدمها، لذا يمكنك إسقاط الاسم، ولكن احتفظ بالأقواس:

size_t array_size(const int (&)[1])

لا يحدث شيء للمصفوفة.إنها معلمة غير مستخدمة تُستخدم لحل توقيع وظيفة القالب.

كما لا يمكن استخدامه كوسيطة قالب، ولكن هذا أمر منفصل.

طريقة غريبة بعض الشيء للحصول على النتيجة كقيمة وقت الترجمة لأولئك منا الذين ليس لديهم "constexpr":

#include <iostream>

namespace
{

    template <size_t V>
    struct helper
    {
        enum
        {
            value = V
        };
    };


    template<typename T, size_t Size>
    auto get_size(T(&)[Size]) -> helper < Size >
    {
        return helper < Size >() ;
    }

    template<typename T>
    struct get_value
    {
        enum
        {
            value = T::value
        };
    };

}

int main()
{
    std::cout << get_value<decltype(get_size("Foo bar baz"))>::value;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top