Qt 5: unable to declare signal that takes rvalue reference

1.7k views Asked by At

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.

2

There are 2 answers

0
Kuba hasn't forgotten Monica On BEST ANSWER

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.

1
Michael Orlov On

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
    }