سؤال

في C# يمكننا تحديد نوع عام يفرض قيودًا على الأنواع التي يمكن استخدامها كمعلمة عامة.يوضح المثال التالي استخدام القيود العامة:

interface IFoo
{
}


class Foo<T> where T : IFoo
{
}

class Bar : IFoo
{
}

class Simpson
{
}

class Program
{
    static void Main(string[] args)
    {
        Foo<Bar> a = new Foo<Bar>();
        Foo<Simpson> b = new Foo<Simpson>(); // error CS0309
    }
}

هل هناك طريقة يمكننا من خلالها فرض قيود على معلمات القالب في C++.


يتمتع C++0x بدعم أصلي لهذا ولكني أتحدث عن المعيار الحالي C++.

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

المحلول

كما ذكر شخص آخر، فإن C++0x يقوم بدمج هذا في اللغة.حتى ذلك الحين، أود أن أوصي بيارن ستروستروباقتراحات لقيود القالب.

يحرر: يعزز لديها أيضا البديل الخاص بها.

تحرير 2:يشبه تمت إزالة المفاهيم من C++ 0x.

نصائح أخرى

إذا كنت تستخدم C++ 11، يمكنك استخدام static_assert مع std::is_base_of لهذا الغرض.

على سبيل المثال،

#include <type_traits>

template<typename T>
class YourClass {

    YourClass() {
        // Compile-time check
        static_assert(std::is_base_of<BaseClass, T>::value, "type parameter of this class must derive from BaseClass");

        // ...
    }
}

"ضمنا" هو الجواب الصحيح.تعمل القوالب على إنشاء سيناريو "كتابة البطة" بشكل فعال، نظرًا للطريقة التي يتم بها تجميعها.يمكنك استدعاء أي وظائف تريدها بناءً على قيمة مكتوبة بالقالب، وعمليات المثيل الوحيدة التي سيتم قبولها هي تلك التي تم تعريف هذه الطريقة لها.على سبيل المثال:

template <class T>
int compute_length(T *value)
{
    return value->length();
}

يمكننا استدعاء هذه الطريقة على المؤشر لأي نوع يعلن عن length() طريقة إرجاع int.وبالتالي:

string s = "test";
vector<int> vec;
int i = 0;

compute_length(&s);
compute_length(&vec);

...ولكن ليس على مؤشر للنوع الذي يفعل ذلك لا يعلن length():

compute_length(&i);

لن يتم تجميع هذا المثال الثالث.

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

يمكنك وضع نوع حماية على IFoo لا يفعل شيئًا، وتأكد من وجوده على T في Foo:

class IFoo
{
public:
    typedef int IsDerivedFromIFoo;
};

template <typename T>
class Foo<T>
{
    typedef typename T::IsDerivedFromIFoo IFooGuard;
}

الدفع يعزز

مكتبة التحقق من مفهوم التعزيز (BCCL)

تتيح مكتبة التحقق من المفهوم إضافة عبارة صريحة والتحقق منها المفاهيم في اسلوب ملحق لغة C++ المقترح.

نوعا ما.إذا قمت بإرسال static_cast إلى IFoo*، فسيكون من المستحيل إنشاء مثيل للقالب ما لم يمرر المتصل فئة يمكن تعيينها إلى IFoo*.

ضمنا فقط.
يتم فرض أي طريقة تستخدمها في طريقة يتم استدعاؤها بالفعل على معلمة القالب.

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

لن يسمح لك المترجم بإنشاء مثيل للقوالب التي تستخدم الإصدار مع المنشئين الخاصين.

يسمح هذا المثال فقط بإنشاء مثيل باستخدام int وfloat.

template<class t> class FOO { private: FOO(){}};

template<> class FOO<int>{public: FOO(){}};

template<> class FOO<float>{public: FOO(){}};

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

انظر إلى نمط CRTP (نمط القالب العودي الغريب).وهي مصممة للمساعدة في دعم الميراث الثابت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top