كيفية دعم المقارنات للكائنات QVariant التي تحتوي على نوع مخصص؟

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

  •  01-10-2019
  •  | 
  •  

سؤال

وفقا لوثائق QT ، QVariant::operator== لا يعمل كما قد يتوقع المرء ما إذا كان المتغير يحتوي على نوع مخصص:

Bool Qvariant :: Operator == (const qvariant & v) const

يقارن هذا qvariant مع V ويعود صحيح إذا كانت متساوية ؛ وإلا يعود خطأ.

في حالة الأنواع المخصصة ، لا يتم استدعاء مشغلي المساواة. بدلاً من ذلك ، تتم مقارنة عناوين القيم.

كيف من المفترض أن تتصرف هذا بشكل مفيد لأنواعك المخصصة؟ في حالتي ، أقوم بتخزين قيمة مُرتب في Qvariant ، على سبيل المثال

في رأس:

enum MyEnum { Foo, Bar };

Q_DECLARE_METATYPE(MyEnum);

في مكان ما في وظيفة:

QVariant var1 = QVariant::fromValue<MyEnum>(Foo);
QVariant var2 = QVariant::fromValue<MyEnum>(Foo);
assert(var1 == var2); // Fails!

ما الذي يجب أن أفعله بشكل مختلف حتى يكون هذا التأكيد صحيحًا؟

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

لا يعتقد أنه من الممكن بالنسبة لي أن أحتاج إلى مقارنات عن المساواة للعمل. السياق هو أنني أستخدم هذا التعداد باعتباره المستخدم في العناصر في أ QComboBox وأريد أن أكون قادرًا على الاستخدام QComboBox::findData لتحديد موقع فهرس العنصر المقابل لقيمة محددة معينة.

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

المحلول

الإجابة الواضحة هي إخراج البيانات مع var1.value<MyEnum>() == var2.value<MyEnum>() لمقارنتها ، ولكن هذا يتطلب منك معرفة النوع عند المقارنة. يبدو أنه في حالتك قد يكون هذا ممكنًا.

إذا كنت تستخدم التعدادات فقط ، فيمكنك أيضًا تحويلها إلى int للتخزين في QVariant.

تحرير: للتوضيح حول البحث أ QComboBox, ، هو - هي يستخدم نموذج مربع التحرير والسرد للعثور على البيانات. على وجه التحديد ، يستخدم match() وظيفة QAbstractItemModel للتحقق من المساواة. لحسن الحظ ، هذه الوظيفة افتراضية حتى تتمكن من تجاوزها في فئة فرعية.

نصائح أخرى

جرب Hack Qvariant ، حدد الوظيفة بواسطة النموذج الأولي

typedef bool (*f_compare)(const Private *, const Private *);

وتعيينها على Qvariant Handler ؛ للعمل مع QVariant QT استخدام معالج:

struct Handler {
    f_construct construct;
    f_clear clear;
    f_null isNull;
  #ifndef QT_NO_DATASTREAM
    f_load load;
    f_save save;
 #endif
    f_compare compare;
    f_convert convert;
    f_canConvert canConvert;
    f_debugStream debugStream;
};

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

class HackVariant : private QVariant
{
public:
     static void hackIt() {
         origh = handler;
         Handler* h = new Handler;
         *h = *origh;
         h->convert = convert;
         h->debugStream = hackStreamDebug;
         handler = h;
     }

private:
     static bool convert(const QVariant::Private *d, QVariant::Type t, void *result, bool *ok)
     {
         //qDebug() << Q_FUNC_INFO << "type:" << d->type;
         if (d->type >= QVariant::UserType)
         {
             QString& str = *((QString*)result);
             Identifier* ident = (Identifier*)(constData(d));
             str = ident->toString();
         }
         else
             return origh->convert(d, t, result, ok);
         return true;
     }

     static void hackStreamDebug(QDebug dbg, const QVariant &v) {
         if (v.canConvert<Identifier>())
             dbg << v.value<Identifier>();
         else
             origh->debugStream(dbg, v);
     }

     static const Handler* origh;

     static const void *constData(const QVariant::Private *d)
     {
         return d->is_shared ? d->data.shared->ptr : reinterpret_cast<const void *>(&d->data.ptr);
     }

};

يجب عليك إنشاء وظيفة وتعيينها على المعالج. لا تنسى المكالمة HackVariant::hackIt() في main.cpp قبل الاستخدام (var1 == var2).

الحل ل QT 5

QT يدعم هذا خارج الصندوق منذ الإصدار 5.2. نرى QVariant :: Operator == و qmetatype :: registercomparators.

الحل ل QT 4

إذا كنت لا تزال تستخدم QT 4 ولا يمكنك (أو لا تريد) الترقية إلى QT 5 حتى الآن ، فيمكنك استخدام CustomVariantComparator الفصل الذي كتبته لأحد مشاريعي.

يمكنك استخدامه على النحو التالي. دعنا نقول أن لدينا فصل Foo الذي ينفذ operator== ويجب استخدامها ضمن أ QVariant:

class Foo {
public:
    bool operator==(const Foo &other) { return ...; }
};
Q_DECLARE_METATYPE(Foo)

ثم ، ببساطة ضع Q_DEFINE_COMPARATOR الماكرو بجوار تنفيذ Foo (أي داخل Foo.cpp الملف ، ولكن ليس داخل Foo.h ملف):

Q_DEFINE_COMPARATOR(Foo)

التالي، بعد، بعدما بناء الخاص بك QApplication (أو QCoreApplicationمثيل ، قم بتمكين المقارنة المتغيرة المخصصة (يجب القيام بذلك مرة واحدة فقط):

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    CustomVariantComparator::setEnabled(true);
    // more code...
}

الآن ، ستعمل مقتطف الكود التالي كما هو متوقع (أي استدعاء Foo::operator==).

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