سؤال

العنوان الأصلي هنا كانالحل البديل لخطأ SFINAE في VS2005 C++

هذا استخدام مبدئي لـ SFINAE لعمل ما يعادل فئة القالب is_pod الموجودة في TR1 (في VS2005 لا يوجد TR1 حتى الآن).ينبغي أن يكون لها قيمة عضو صحيح عندما تكون معلمة القالب من نوع POD (بما في ذلك الأنواع البدائية والبنيات المصنوعة منها) وخطأ عندما لا تكون كذلك (كما هو الحال مع المنشئات غير التافهة).

template <typename T> class is_pod
{
  public:

    typedef char Yes;
    typedef struct {char a[2];} No;

    template <typename C> static Yes test(int)
    {
      union {T validPodType;} u;
    }
    template <typename C> static No test(...)
    {
    }
    enum {value = (sizeof(test<T>(0)) == sizeof(Yes))};
};

class NonPOD
{
  public:
    NonPod(const NonPod &);
    virtual ~NonPOD();
};

int main()
{
  bool a = is_pod<char>::value;
  bool b = is_pod<NonPOD>::value;
  if (a) 
    printf("char is POD\n");
  if (b)
    printf("NonPOD is POD ?!?!?\n");
  return 0;
}

المشكلة هي أن VS 2005 ليس فقط لا يحتوي على TR1، بل لن يهتم بالاتحاد أعلاه (والذي لا ينبغي أن يكون صالحًا عندما لا تكون معلمة القالب POD)، لذا يتم تقييم كل من a وb على أنه صحيح.


شكرا على الإجابات المنشورة أدناه.بعد قراءتها بعناية (والرمز) أدركت أن ما كنت أحاول القيام به كان حقًا أسلوبًا خاطئًا.كانت الفكرة هي الجمع بين سلوك SFINAE والتكيف مع القالب must_be_pod (الذي وجدته في الكتاب لغة C++ غير كاملة, ولكن يمكن العثور عليه في أماكن أخرى أيضًا).في الواقع، قد يتطلب هذا مجموعة محددة تمامًا من القواعد لـ SFINAE، وهي ليست ما يحدده المعيار بوضوح.هذا ليس خطأً حقيقيًا في VS، بعد كل شيء.

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

المحلول

أكبر مشكلة في أسلوبك هي أنك لا تفعل SFINAE هنا - ينطبق SFINAE فقط على أنواع المعلمات ونوع الإرجاع هنا.

ومع ذلك، من بين جميع حالات SFINAE في المعيار، لا ينطبق أي منها على موقفك.هم

  • صفائف فارغة أو مراجع أو وظائف أو ذات حجم غير صالح
  • نوع العضو الذي ليس من النوع
  • مؤشرات إلى مراجع، إشارات إلى مراجع، إشارات إلى باطلة
  • مؤشر إلى عضو من نوع غير فئة
  • تحويلات غير صالحة لمعلمات قيمة القالب
  • أنواع الوظائف مع الوسائط من النوع void
  • نوع الدالة const/المتقلبة

ربما لهذا السبب يوجد في وثائق Boost ما يلي:

بدون مساعدة (حتى الآن غير محددة) من برنامج التحويل البرمجي ، لن يبلغ ISPOD أبدًا أن الفصل أو البنية عبارة عن جراب ؛هذا آمن دائمًا ، إن كان من المحتمل أن يكون دون المستوى الأمثل.حاليًا (مايو 2005) فقط MWCW 9 و Visual C ++ 8 لديهما برنامج التحويل البرمجي الضروري.

نصائح أخرى

هذا لا يعمل مع VS2008 أيضًا، ولكن أظن أنك تعرف ذلك أيضًا.SFINAE مخصص لاستنتاج وسيطات القالب لمعلمات القالب؛لا يمكنك حقًا استنتاج نوع الشيء الذي يكشف عن مُنشئ النوع، على الرغم من أنه يمكنك إنشاء نوع غير متوافق مع نوع آخر (على سبيل المثال، لا يمكن للنقابات استخدام غير POD).

في الواقع، يستخدم VS 2008 دعم المترجم للسمات المراد تنفيذها std::tr1::type_traits.

لست متأكدًا من الطريقة التي تحاول بها القيام بـ SFINAE هنا منذ ذلك الحين is_pod<T>::test(...) سيطابق is_pod<T>::test(0) أيضاً.ربما إذا استخدمت نوعًا مختلفًا بدلاً من "int" فستحصل على تطابق أفضل:

template <typename T> class is_pod
{
  struct my_special_type { };
  public:
    typedef char Yes;
    typedef struct {char a[2];} No;

    template <typename C> static Yes test(my_special_type)
    {
      union {T validPodType;} u;
    }

    template <typename C> static No test(...)
    {
    }
    enum {value = (sizeof(test<T>(my_special_type())) == sizeof(Yes))};
};

قد ترغب أيضًا في إلقاء نظرة على Boost.Enable_if للقيام بـ SFINAE نيابةً عنك - إلا إذا كنت تحاول تنفيذ مكتبتك الخاصة أو لسبب ما.

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