سؤال

لدينا مشروع فرعي "CACEUTILS" له العديد من مقتطفات الكود العام المستخدمة في جميع أنحاء المشروع الأم. واحدة من هذه الأشياء المثيرة للاهتمام رأيت هي: -

/*********************************************************************
If T is polymorphic, the compiler is required to evaluate the typeid 
stuff at runtime, and answer will be true.  If T is non-polymorphic, 
the compiler is required to evaluate the typeid stuff at compile time, 
whence answer will remain false
*********************************************************************/
template <class T> 
bool isPolymorphic() { 
   bool answer=false; 
   typeid(answer=true,T()); 
   return answer; 
}

ورأيت التعليق واعتقدت أنها قالب مثيرة للاهتمام رغم أنه لا يستخدم في جميع أنحاء المشروع. حاولت استخدامها مثل هذا فقط للفضول ...

class PolyBase {
public:
   virtual ~PolyBase(){}
};

class NPolyBase {
public:
   ~NPolyBase(){}
};


if (isPolymorphic<PolyBase>())
  std::cout<<"PolyBase = Polymorphic\n";
if (isPolymorphic<NPolyBase>())
  std::cout<<"NPolyBase = Also Polymorphic\n";

لكن أيا من أولئك الذين يعودون بسهولة. لا يعطي MSVC 2005 أي تحذيرات، لكن comeau يحذر التعبير مع عدم وجود تأثير. القسم 5.2.8 في معيار C ++ لا يقول أي شيء مثل ما يقوله التعليق، كما يتم تقييم IE ElefectID في وقت ترجمة الأنواع غير المرئية ووقت التشغيل لأنواع متعددة الأشكال.

1) لذلك أعتقد أن التعليق مضلل / خطأ عادي أو لأن مؤلف هذا الرمز هو مبرمج كبار C ++، هل أنا أفتقد شيئا؟

2) Otoh، أتساءل عما إذا كان بإمكاننا اختبار ما إذا كان الفصل متعدد الجنس (يحتوي على وظيفة افتراضية واحدة على الأقل) باستخدام بعض التقنيات؟

3) متى يرغب المرء في معرفة ما إذا كان الفصل متعدد الجنس؟ تخمين البرية للحصول على عنوان بدء الفصل باستخدام dynamic_cast<void*>(T) (كما dynamic_cast يعمل فقط على الطبقات متعددة الجنس).

في انتظار آرائكم.

شكرا مقدما،

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

المحلول

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

تحديث: يبدو أنني مخطئ فعلا. النظر في هذا البديل:

template <class T> 
bool isPolymorphic() { 
    bool answer=false;
    T *t = new T();
    typeid(answer=true,*t); 
    delete t;
    return answer; 
}

هذا فعلا يعمل العمل كما يوحي الاسم، بالضبط التعليق في مقتطف التعليمات البرمجية الأصلية. لا يتم تقييم التعبير الداخلي من المعرفة إذا كان "لا يعين انخفاضا من نوع الطبقة متعددة الجنس" (STD 3.2 / 2). لذلك، في حالة أعلاه، إذا لم يكن T متعدد المراحل، فلن يتم تقييم تعبير المعرفة. إذا كانت T متعددة المرء، فإن * T هي بالفعل lvalue من النوع متعدد الأشكال، لذلك يجب تقييم تعبير كامل.

الآن، مثالك الأصلي لا يزال خطأ :-). تستخدم T(), ، ليس *t. وبعد و T() يزيد rvalue. (STD 3.10 / 6). لذلك، فإنه لا يزال يعطي تعبيرا ليس "lvalue من الطبقة متعددة الجنسيات".

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

نصائح أخرى



class PolyBase {
public:   
    virtual ~PolyBase(){}
};

class NPolyBase {
public:
    ~NPolyBase(){}
};

template<class T>
struct IsPolymorphic
{
    struct Derived : T {
        virtual ~Derived();
    };
    enum  { value = sizeof(Derived)==sizeof(T) };
};


void ff()
{
    std::cout << IsPolymorphic<PolyBase >::value << std::endl;
    std::cout << IsPolymorphic<NPolyBase>::value << std::endl;
}

منذ C ++ 11، هذا متاح الآن في <type_traits> رأس as. std::is_polymorphic. وبعد يمكن استخدامه مثل هذا:

struct PolyBase {
  virtual ~PolyBase() {}
};

struct NPolyBase { 
  ~NPolyBase() {}
};

if (std::is_polymorphic<PolyBase>::value)
  std::cout << "PolyBase = Polymorphic\n";
if (std::is_polymorphic<NPolyBase>::value)
  std::cout << "NPolyBase = Also Polymorphic\n";

هذا يطبع فقط "polybase = polymorphic".

يمكن للمرء استخدام الحقائق التي:

  1. dynamic_cast فشل في تجميع الوقت إذا كانت الوسيطة ليست فئة متعددة الأشكال. بحيث يمكن استخدامها مع Sfinae.
  2. dynamic_cast<void*> هو مقدس صالح يعيد عنوان اكتمال كائن متعدد الأشكال.

وبالتالي، في C ++ 11:

#include <iostream>
#include <type_traits>

template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});

template<class T>
auto is_polymorphic2_test(...) -> std::false_type;

template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));

struct A {};
struct B { virtual ~B(); };

int main() {
    std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
    std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}

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

بالتأكيد إذا كنت ترغب في معرفة ما إذا كان الفصل متعدد الجنس، فكل ما عليك فعله هو أن تسأل ما إذا كان يدعم dynamic_cast, ، أليس هذا صحيح؟

template<class T, class> struct is_polymorphic_impl   : false_type {};
template<class T> struct is_polymorphic_impl
    <T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {};

template<class T> struct is_polymorphic :
    is_polymorphic_impl<remove_cv_t<T>, void*> {};

هل يمكن لأي شخص أن يشير إلى عيب في هذا التنفيذ؟ أتصور أنه يجب أن يكون هناك واحد، أو يجب أن يكون واحدا في مرحلة ما في الماضي، لأن وثائق دفعة. يواصل الادعاء بذلك is_polymorphic "لا يمكن تنفيذها جولة في لغة C ++".

ولكن "portably" هو نوع من كلمة ابن عرس، أليس كذلك؟ ربما يخلوهم فقط كيفية دعم MDVC التعبير - Sfinae، أو بعض اللهجات مثل C ++ المضمنة لا تدعم dynamic_cast. وبعد ربما عندما يقولون "لغة C ++" تعني "مجموعة فرعية أقل شائعة من لغة C ++." لكن لدي شك في مزعج ربما يعني ما يقولون، و انا الشخص الذي يفتقد شيئا ما.

ال typeid كما يبدو النهج في البروتوكول الأول المرئي (بصيغته المعدلة من خلال إجابة لاحقة لاستخدام lvalue وليس زالو) على ما يرام، ولكن بالطبع ليس constexpr ويتطلب بناء في الواقع T, ، والتي قد تكون باهظة الثمن. إذا هذا dynamic_cast النهج يبدو أفضل ... إلا إذا لم يعمل لسبب ما. أفكار؟

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