Qt 5: unable to declare signal that takes rvalue reference
Asked Answered
A

2

10

Probably I've missed something, but I can't find any information that signals can't take rvalue references.

So, I have a class with the following signal declaration:

signals:
   void messageDecoded(HTDataMsg &&msg);

When I try to compile it, I got errors:

moc_htcodec.cpp: In static member function ‘static void HTCodec::qt_static_metacall(QObject*, QMetaObject::Call, int, void**)’:
moc_htcodec.cpp:71:77: error: cannot bind ‘HTDataMsg’ lvalue to ‘HTDataMsg&&’
         case 0: _t->messageDecoded((*reinterpret_cast< HTDataMsg(*)>(_a[1]))); break;
                                                                             ^
In file included from moc_htcodec.cpp:9:0:
../hterm_core/htcodec/htcodec.h:59:9: error:   initializing argument 1 of ‘void HTCodec::messageDecoded(HTDataMsg&&)’
    void messageDecoded(HTDataMsg &&msg);
         ^
make: *** [moc_htcodec.o] Error 1

And the code in generated moc-file is indeed wrong:

void HTCodec::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        HTCodec *_t = static_cast<HTCodec *>(_o);
        switch (_id) {
        case 0: _t->messageDecoded((*reinterpret_cast< HTDataMsg(*)>(_a[1]))); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {
        int *result = reinterpret_cast<int *>(_a[0]);
        void **func = reinterpret_cast<void **>(_a[1]);
        {
            typedef void (HTCodec::*_t)(HTDataMsg && );
            if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&HTCodec::messageDecoded)) {
                *result = 0;
            }
        }
    }
}

Is this behavior expected? Is it illegal for signals to take rvalue references?

If I change HTDataMsg &&msg to, say, const HTDataMsg &msg, then of course it works.

Analyze answered 16/6, 2015 at 17:5 Comment(3)
Why do you want to signal with rvalue-references (and think that they may have several receivers for that) ?Angloamerican
Hmm. I wanted them to avoid copy overhead, but, well, I haven't thought about several receivers (although they are impossible in my particular application). Ok, my bad, they are illegal indeed. Thanks.Analyze
If you know they are illegal, take a & and move out of it. Be careful.Tectonics
C
10

Is it illegal for signals to take rvalue references?

Yes. It makes no sense for them to take rvalue references, since the number of receivers is a non-negative integer. Rvalue references would only make sense for the special case of zero or one receiver, and even then, it'd require a C++11-only version of Qt.

If you think that such an optimization makes sense for common data types (measure and back your assertions by benchmarks!), it could be implemented for Qr 5.7 onwards, since it requires C++11 support by the platform. This would need support from moc as well as from the library itself.

Coriolanus answered 16/6, 2015 at 18:33 Comment(0)
C
2

If you need to use memory move for case with one signal and only one slot you can pass object by simple reference not 'const' and then use move semantic inside slot. Here is some simple example:

class PcapPacket {
    public:
        PcapPacket();
        std::vector<uint8_t>&& getData() {
          return std::move(_vData);
        }
    private:
        std::vector<uint8_t> _vData;
    };

    signals:
        void packet(PcapPacket& pcapPacket);


 // Register types for signals
 qRegisterMetaType<PcapPacket>("PcapPacket&");

    connect(pcapReader, &PcapReader::packet, controlItem, &SensorControlItem::processPcapPacket);
 //   connect(_pcapReader, SIGNAL(packet(PcapPacket&)), controlItem, SLOT(processPcapPacket(PcapPacket&)));

    void SensorControlItem::processPcapPacket(PcapPacket& packet) {
      _sensor->processPcapPacket(packet.getData());
    }

    void sensor::processPcapPacket(std::vector<uint8_t>&& data) {
      // Do here with data what ever you want. It's yours without memory copy
    }
Chromatolysis answered 19/12, 2018 at 23:33 Comment(1)
This works only for slots in the same thread. For cross-thread signal/slot connections there appears to be no way to avoid a copy.Meyerhof

© 2022 - 2024 — McMap. All rights reserved.