Qt 5:无法声明采用右值引用的信号

Qt 5: unable to declare signal that takes rvalue reference

本文关键字:引用 信号 声明 Qt      更新时间:2023-10-16

可能我错过了一些东西,但我找不到任何信号不能接受右值引用的信息。

因此,我有一个具有以下信号声明的类:

signals:
   void messageDecoded(HTDataMsg &&msg);

当我尝试编译它时,我遇到了错误:

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

生成的moc文件中的代码确实是错误的:

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;
            }
        }
    }
}

这种行为是预期的吗?信号采用右值引用是否违法?

如果我HTDataMsg &&msg更改为,比如说,const HTDataMsg &msg,那么它当然有效。

信号采用右值引用是否违法?

是的。它们采用右值引用是没有意义的,因为接收器的数量是一个非负整数。Rvalue引用只对零个或一个接收器的特殊情况有意义,即使这样,它也需要一个仅限C++11版本的Qt。

如果您认为这样的优化对常见数据类型有意义(通过基准测试来衡量和支持您的断言!),则可以在 Qr 5.7 及更高版本中实现,因为它需要平台的 C++11 支持。这需要moc以及图书馆本身的支持。

如果您需要对一个信号和一个插槽的情况使用内存移动,您可以通过简单的引用而不是"const"传递对象,然后在插槽内使用移动语义。下面是一些简单的例子:

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
    }