سؤال

أحتاج إلى قالب مثل هذا، والذي يعمل بشكل مثالي

template <typename container> void mySuperTempalte (const container myCont)
{
    //do something here
}

ثم أرغب في تخصيص القالب أعلاه لـ std::string لذلك توصلت إلى هذا

template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
    //check type of container
    //do something here
}

الذي لا يعمل، ويلقي خطأ.أرغب في تشغيل المثال الثاني، ثم أود، إذا أمكن، إضافة بعض التعليمات البرمجية في القالب للتحقق مما إذا تم استخدام قائمة std::vector/std::deque/std::list، للقيام بشيء مختلف في كل منها قضية.لذلك استخدمت القوالب لأن 99% من الكود هو نفسه بالنسبة لكل من المتجهات وdeques وما إلى ذلك.

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

المحلول

إذا أنا فهم المشكلة بشكل صحيح لديك خوارزمية التي ستعمل ناقلات حاويات STL، صف مزدوج الذيل وغيرها ولكن تحاول إرسال التخصص قالب للسلسلة. إذا كان هذا هو الحال بعد ذلك يمكنك كتابة طريقة قالب المعمم الذي قمت بتعريفه في سؤالك: -

template<typename container> void mySuperTempalte( const container &myCont )
{
    // Implement STL container code
}

وبعد ذلك للتخصص سلسلة الخاص بك تقوم بتعريف: -

template<> void mySuperTempalte( const container<std::string> &myCont )
{
    // Implement the string code
}

لأي من التخصصات الأخرى مجرد تغيير تعريف نوع لmyCont. إذا كنت حقا بحاجة للقيام بذلك لناقلات وحاويات صف مزدوج الذيل ثم جعل المعلمة قالب المعلمة لنوع في تلك الحاوية بدلا من الحاوية نفسها كما اقترح سبتمبر

template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
    // check type of container
    // do something here
}

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

وعلى الجانب علما، لقد تغيرت المعلمة الحاويات إلى مرجع CONST، افترض أن هذا هو ما تريد، كما تقوم بتعريف CONST الكائن على أي حال، وبهذه الطريقة يمكنك تجنب نسخة.

نصائح أخرى

لمتخصصون:

template<> void mySuperTempalte<std:string>(const std::string myCont)
{
    //check type of container
    //do something here
}

لمتخصصون لناقلات:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

لتتخصص في صف مزدوج الذيل:

template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
    //check type of container
    //do something here
}

هل حاولت معلمة typename القالب؟ بناء الجملة غريبة بعض الشيء لأنه يحاكي بناء الجملة تستخدم ل<م> أعلن مثل وعاء. هناك المادة InformIT شرح هذا في مزيد من التفاصيل.

template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}

لاحظ أن عليك أيضا أن تعلن الحجة كمرجع!

وبالمناسبة: هذا التعليق

//check type of container

وهو الهبة الميتة التي كنت تفعل شيئا خاطئا. تفعل <م> لا تريد أن تحقق نوع من الحاوية. العضو الأكثر تطورا الحمولة الزائدة بدلا من ذلك، كما هو مبين في الجواب سبتمبر و.

والأجوبة يبدو حتى الآن مفيدة، ولكن أنا أعتقد أن استخدام بناء مختلفة. أتوقع جميع الحاويات لتحديد قيمة VALUE_TYPE، تماما مثل حاويات STL القيام به. لذلك، أستطيع أن أكتب

inline template <typename C> void mySuperTemplate (C const& myCont)
{
    mySuperTemplateImpl<C, typename C::value_type>(myCont);
}

في عام، فإنه من السهل أن تعمل على المعلمة التي قمت استخراج صراحة.

@ سبتمبر

'حل بسيط

تعد الإجابة التي نشرها "sep" جيدة جدًا، وربما تكون جيدة بما يكفي لـ 99% من مطوري التطبيقات، ولكن يمكن الاستفادة من بعض التحسين إذا كانت جزءًا من واجهة المكتبة، للتكرار:

للتخصص في المتجهات:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

سيعمل هذا بشرط ألا يستخدم المتصل std::vector.إذا كان هذا يعمل بشكل جيد بالنسبة لك، للتخصص في المتجهات، والقائمة، وما إلى ذلك، فتوقف هنا واستخدم ذلك فقط.

حل أكثر اكتمالا

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

أحد الأساليب للقيام بذلك هو استخدام تقنية Enable_if - تسمح لك Enable_if بإخراج التحميل الزائد لقالب الوظيفة بشكل انتقائي من قائمة المطابقة المحتملة باستخدام قاعدة لغة غامضة...في الأساس، إذا كان بعض التعبير المنطقي خاطئًا، يصبح الحمل الزائد "غير مرئي".ابحث عن SFINAE لمزيد من المعلومات إذا كنت فضوليًا.

مثال.يمكن تجميع هذا الرمز من سطر الأوامر باستخدام MinGW (g++ بارامتراتيز.cpp) أو VC9 (cl /EHsc بارامتراتيز.cpp) بدون أخطاء:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };

template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };

namespace detail{
    // our special function, not for strings
    //   use ... to make it the least-prefered overload
    template <class Container>
    void SpecialFunction_(const Container& c, ...){
        cout << "invoked SpecialFunction() default\n";
    }

    // our special function, first overload:
    template <class Container>
    // enable only if it is a container of mutable strings
    typename enable_if<
        is_same<typename Container::value_type, string>::value, 
        void
    >::type
    SpecialFunction_(const Container& c, void*){
        cout << "invoked SpecialFunction() for strings\n";
    }
}

// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
    detail::SpecialFunction_(c, 0);
}

int main(){
    vector<int> vi;
    cout << "calling with vector<int>\n";
    SpecialFunction(vi);

    vector<string> vs;
    cout << "\ncalling with vector<string>\n";
    SpecialFunction(vs);
}

انتاج:

d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default

calling with vector<string> invoked
SpecialFunction() for strings

d:\scratch>

هل هو التصميم الجيد أو لم يبق لمزيد من المناقشة. على أي حال، يمكنك الكشف عن نوع الحاوية باستخدام التخصصات قالب جزئية. على وجه الخصوص:

enum container_types
{
   unknown,
   list_container,
   vector_container
};

template <typename T>
struct detect_container_
{
   enum { type = unknown };
};

template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
   enum { type = vector_container };
};

template <typename V>
struct detect_container_< std::list<V> >
{
   enum { type = list_container };
};

// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
   return static_cast<container_types>( detect_container_<T>::type );
}

int main()
{
   std::vector<int> v;

   assert( detect_container( v ) == vector_container );
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top