C ++: القيم الافتراضية لحجج قالب غير مشاركة منها؟

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

سؤال

ولدي قالب الطبقة الحاوية التي تبدو مثل هذا:

template<
   class KeyType, 
   class ValueType, 
   class KeyCompareFunctor   = AnObnoxiouslyLongSequenceOfCharacters<KeyType>, 
   class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType> 
>
   class MyClass
   {
      [...]
   }

وهذا يعني أنني عندما مثيل كائن من هذه الفئة، وأستطيع أن أفعل ذلك بعدة طرق مختلفة:

MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;

وهذه هي كل شيء جيد. وتأتي المشكلة عندما أريد أن مثيل MyClass يستخدم نسخة غير الافتراضية من ذي الحجة ValueCompareFunctor، ولكن ما زلت تريد استخدام القيمة الافتراضية للحجة KeyCompareFunctor. ثم لا بد لي أن أكتب هذا:

MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;

وسيكون أكثر ملاءمة إذا كنت قد حذفت بطريقة أو بأخرى الوسيطة الثالثة ومجرد كتابة هذا:

MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;

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

هل هناك طريقة للقيام بذلك في C ++؟

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

المحلول

في عام، سواء في قوالب ووظائف أو الأساليب، C ++ يتيح لك استخدام الافتراضي ل(وبالتالي حذف) فقط <م> زائدة المعلمات - لا سبيل للخروج

وأوصي قالب أو ماكرو لتقصير AnObnoxiouslyLongSequenceOfCharacters<MyKeyType> إلى Foo<MyKeyType> - لم يكن مثاليا، ولكن أفضل من لا شيء

.

نصائح أخرى

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

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

ويمكن تطبيق نفس النهج على حجج القالب. بدلا من الحجج قالب N + P اختياري منها، إنشاء فئة الخاص بك مع الحجج N + 1 قالب. آخر واحد سوف يعقد "المسمى" المعلمات التي يمكن حذفها.

وهذا الجواب لم يكتمل بعد، ولكن آمل أن تكون هذه بداية جيدة!

وخيار بديل هو استخدام الطبقات الصفات:

template <class KeyType>
class KeyTraits
{
  typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> Compare;
};

template <class ValueType>
class ValueTraits
{
  typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>  Compare;
};

template<class KeyType class ValueType>
class MyClass
{
  typedef KeyTraits<KeyType>::Compare KeyCompareFunctor;
  typedef ValueTraits<ValueType>::Compare KeyCompareFunctor;
};

وبعد ذلك إذا كان لديك النوع الذي يحتاج إلى وظيفة مقارنة مختلفة لفي مفتاح، ثم كنت متخصصون صراحة KeyTraits اكتب عن هذه الحالة. وإليك مثال حيث أننا تغييره int:

template <>
class KeyTraits<int>
{
  typedef SpecialCompareForInt Cmopare;
};

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

template<class KeyType, 
         class ValueType, 
         class Pol1 = DefaultArgument, 
         class Pol2 = DefaultArgument>
class MyClass {
    typedef use_policies<Pol1, Pol2> policies;

    typedef KeyType key_type;
    typedef ValueType value_type;
    typedef typename policies::
      template apply_key_compare<KeyType>::type 
      key_compare;
    typedef typename policies::
      template apply_value_compare<ValueType>::type 
      value_compare;
};

والآن، لديهم حجة الافتراضية التي تستخدمها، والتي لديها typedefs للوسائط الافتراضية التي تريد تقديمها. سيتم معلمات القوالب الأعضاء من خلال أنواع مفتاح وقيمة

struct VirtualRoot { 
  template<typename KeyType>
  struct apply_key_compare {
    typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> 
      type;
  };
  template<typename ValueType>
  struct apply_value_compare {
    typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType> 
      type;
  };
};

struct DefaultArgument : virtual VirtualRoot { };

template<typename T> struct KeyCompareIs : virtual VirtualRoot {
  template<typename KeyType>
  struct apply_key_compare {
    typedef T type;
  };
};

template<typename T> struct ValueCompareIs : virtual VirtualRoot {
  template<typename ValueType>
  struct apply_value_compare {
    typedef T type;
  };
};

والآن، سوف use_policies تستمد من كل الحجج القالب. حيث فئة مشتقة من VirtualRoot يخفي عضو من القاعدة، أن عضوا في فئة مشتقة هو المهيمن على عضو في القاعدة، وسوف تستخدم، على الرغم من أن أعضاء الفئة الأساسية ويمكن الوصول من طريق آخر في شجرة الميراث .

ملحوظة أنك لا تدفع للالميراث الظاهري، لأنك لا إنشاء كائن من نوع use_policies. عليك فقط استخدام الميراث الظاهري للاستفادة من قاعدة الهيمنة.

template<typename B, int>
struct Inherit : B { };

template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };

ولأننا يحتمل أن تكون مستمدة من نفس الفئة أكثر من مرة، ونحن نستخدم Inherit قالب فئة: وراثة نفس الفئة مباشرة مرتين هو ممنوع. ولكن بشكل غير مباشر وراثة مسموح به. يمكنك الآن استخدام كل هذا كما يلي:

MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top