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.

Dmitry Frank
  • 10,417
  • 10
  • 64
  • 114
  • 3
    Why do you want to signal with rvalue-references (and think that they may have several receivers for that) ? – Jarod42 Jun 16 '15 at 17:07
  • 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. – Dmitry Frank Jun 16 '15 at 17:09
  • 1
    If you know they are illegal, take a `&` and `move` out of it. Be careful. – Yakk - Adam Nevraumont Jun 16 '15 at 18:20

2 Answers2

9

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.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
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
    }
Andrew Fan
  • 1,313
  • 5
  • 17
  • 29
Michael Orlov
  • 71
  • 1
  • 3
  • 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. – dqbydt Apr 14 '21 at 23:20