2

で参照として渡された引数をキャプチャすることはできませんQSignalSpy

QSignalSpy spy( myObject, SIGNAL(foo(int&)));

...
int& i=spy.at(0).at(0).value<int&>();

aQVariantには参照メンバーを含めることができないためです。平易な論理。

しかし、渡された引数をチェックする他の解決策はありますか?

4

2 に答える 2

3

Qt 5 以降では、単純connectにラムダ関数を使用できるようになりました。これにより、QSignalSpy不要なものが使用されます。

std::vector<Value> values;
QObject::connect(myObject, &MyObject::foo,
    [&](const auto &value)
    { values.emplace_back(value); });

myObject.somethingCausingFoo();

ASSERT_EQ(1u, values.size());
EXPECT_EQ(expectedValue, values.at(0));
于 2016-03-08T09:32:25.070 に答える
1

「醜い解決策」はQSignalSpy、参照が渡された引数を処理するために、かなり単純なコードをハックすることです。int参照引数の最小限の実例を提供します。initArgsおよびappendArgs関数にのみ変更が加えられました。

このアプローチでは、渡された引数の値を参照によってのみ確認できることに注意してください。その値を変更することはできません。

関数では、initArgs引数による参照があるかどうかを確認し、shouldreinterpretリストに入力します。

void initArgs(const QMetaMethod &member)
{
    QList<QByteArray> params = member.parameterTypes();
    for (int i = 0; i < params.count(); ++i) {
       int tp = QMetaType::type(params.at(i).constData());
       if (tp == QMetaType::Void)
       {
           qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
                    params.at(i).constData());
           // Check if we have a reference by removing the & from the parameter name
           QString argString(params.at(i).constData());
           argString.remove("&");
           tp = QMetaType::type(argString.toStdString().c_str());
           if (tp != QMetaType::Void)
              shouldReinterpret << true;
        }
        else
            shouldReinterpret << false;
        args << tp;
     }
}

appendArgs参照引数で渡されたものを再解釈する関数:

void appendArgs(void **a)
{
    QList<QVariant> list;
    for (int i = 0; i < args.count(); ++i) {
        QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
    if (shouldReinterpret.at(i))
    {
            switch (type)
        {
        case QMetaType::Int:
            list << QVariant(type, &(*reinterpret_cast<int*>(a[i + 1])));
            break;
                // Do the same for other types  
        }
    }
    else
        list << QVariant(type, a[i + 1]);
    }
    append(list);
}

参照用の完全なコード:

class MySignalSpy: public QObject, public QList<QList<QVariant> >
{
public:
    MySignalSpy(QObject *obj, const char *aSignal)
    {
#ifdef Q_CC_BOR
        const int memberOffset = QObject::staticMetaObject.methodCount();
#else
        static const int memberOffset = QObject::staticMetaObject.methodCount();
#endif
        Q_ASSERT(obj);
        Q_ASSERT(aSignal);

        if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
            qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
            return;
        }

        QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
        const QMetaObject *mo = obj->metaObject();
        int sigIndex = mo->indexOfMethod(ba.constData());
        if (sigIndex < 0) {
            qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
            return;
        }

        if (!QMetaObject::connect(obj, sigIndex, this, memberOffset,
                    Qt::DirectConnection, 0)) {
            qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
            return;
        }
        sig = ba;
        initArgs(mo->method(sigIndex));
    }

    inline bool isValid() const { return !sig.isEmpty(); }
    inline QByteArray signal() const { return sig; }


    int qt_metacall(QMetaObject::Call call, int methodId, void **a)
    {
        methodId = QObject::qt_metacall(call, methodId, a);
        if (methodId < 0)
            return methodId;

        if (call == QMetaObject::InvokeMetaMethod) {
            if (methodId == 0) {
                appendArgs(a);
            }
            --methodId;
        }
        return methodId;
    }

private:
    void initArgs(const QMetaMethod &member)
    {
        QList<QByteArray> params = member.parameterTypes();
        for (int i = 0; i < params.count(); ++i) {
            int tp = QMetaType::type(params.at(i).constData());
            if (tp == QMetaType::Void)
            {
                qWarning("Don't know how to handle '%s', use qRegisterMetaType to register it.",
                         params.at(i).constData());

                QString argString(params.at(i).constData());
                argString.remove("&");
                tp = QMetaType::type(argString.toStdString().c_str());
                if (tp != QMetaType::Void)
                    shouldReinterpret << true;
            }
            else
                shouldReinterpret << false;
            args << tp;
        }
    }

    void appendArgs(void **a)
    {
        QList<QVariant> list;
        for (int i = 0; i < args.count(); ++i) {
            QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
            if (shouldReinterpret.at(i))
            {
                switch (type)
                {
                case QMetaType::Int:
                    int k = (*reinterpret_cast<int*>(a[i + 1]));
                    list << QVariant(type, &k);
                    break;
                }
            }
            else
                list << QVariant(type, a[i + 1]);
        }
        append(list);
    }

    // the full, normalized signal name
    QByteArray sig;
    // holds the QMetaType types for the argument list of the signal
    QList<int> args;
    // Holds the indexes of the arguments that 
    QList<bool> shouldReinterpret;
};
于 2013-01-10T16:00:13.370 に答える