首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >用于模板类型推导的QObject多重继承的复杂性

用于模板类型推导的QObject多重继承的复杂性
EN

Stack Overflow用户
提问于 2018-12-20 02:43:45
回答 1查看 136关注 0票数 0

背景

我相信我已经想出了一个解决方案来解决Qt中臭名昭著的模板信号和插槽问题。对于初学者,我定义了一个空的基类Message,它的唯一目的是继承并创建具体的TMessage实现。在Qt中,虽然可以将信号连接到函数器(而不是Qt槽),但信号不能是模板函数,所以我的解决方案是对Message类的关系进行建模,创建一个抽象的Messenger类,使用void signal_Message(Message)信号和template <typename T> void slot_T(TMessage<T>)。然后我遇到了this question和这个问题,并意识到这是一个更易维护的解决方案,我基本上创建了一堆Messenger。当使用不支持的类型时,even代码在编译时失败,并显示一条漂亮的、可读的错误消息:invalid initialization of reference of type Messenger<double>& from expression of type MessengerBag<int, char>

问题

考虑我们使用6种不同的类型,intfloatchardouble、一些enum和一个struct。这将产生一个96字节的sizeof!然而,假设期望的用法是针对有超过50个用户定义类型的地方,每个类型都有自己单独维护的信号和插槽容器,看起来我的解决方案似乎可以用大约相同的开销执行相同的任务,但几乎没有维护成本。除了不再需要维护24个单独的函数的明显好处之外,在复杂的继承方案中可能会有更多的好处,这种方法是否有缺点?在做了一些初步测试后,我发现MessengerBag基本上与菱形图案相反。每个析构函数都是相应地调用的,所以与复合结构相比,我几乎看不到任何缺点,复合结构需要另一个级别(我认为是不必要的和模糊的)间接寻址。Qt本质上轻视虚拟继承,并在直接继承QObject的类中禁止它:因此,我不能像我所希望的那样使Mock成为虚拟的。

示例

// Message.h
struct Message {};
template <typename T> struct TMessage {
    T t
};

// Messenger.h
struct Messenger : public QObject {
    Q_OBJECT
public:
    template <typename T> void slot_doSomethingWithMsg(const Message& msg){
        const auto& tmsg = static_cast<const TMessage<T>&>(msg);
        qDebug() << tmsg.t;
        // do something else... this is just example usage
    }
signals:
    void signal_sendMsg(const BaseMsg& msg);

// MessengerBag.h

template <typename T, typename... Args>
struct MessengerBag : TMessenger<T>, MessengerBag<Args...>{};

template <typename T> struct MessengerBag<T> : TMessenger<T>{};

// Manager.h

MessengerBag<int, char> messengerBag;

Manager(){
    QObject::connect(static_cast<TMock<int>*>(messengerBag),
                     &Mock::signal_sendMsg, 
                     static_cast<TMock<int>*>(messengerBag),
                     &Mock::slot_doSomethingWithMsg<int>);

    QObject::connect(static_cast<TMock<char>*>(messengerBag),
                     &Mock::signal_sendMsg, 
                     static_cast<TMock<char>*>(messengerBag),
                     &Mock::slot_doSomethingWithMsg<char>);

template <typename T> void slot_sendMsg(const TMessage<T>& msg){
    TMessenger<T>& messenger = messengerBag;
    messenger.signal_sendMsg(msg);
}

// main.cpp

auto* manager = new Manager();

TMessage<int> imsg{5};
TMessage<char> cmsg{'f'};

manager->slot_sendMsg(imsg);
manager->slot_sendMsg(cmsg);

正如预期的那样,上面的示例打印5和'f',从而用模板信号和插槽破坏了这个问题。然而,我在看到未来可能出现的任何问题时遇到了一些问题。当然,一个问题是QObject是不可访问的,因为哪个QObject仍然是未知的,组合解决方案可能会调解(将TMessenger委托给Messenger,并且MessengerBag在空的Args专门化中继承QObject )。在没有首先了解其可能的缺点的情况下,我会犹豫是否要致力于这个解决方案。此外,请随时在代码本身上留下注释。

tl;dr

Qt信号调用函数器,但信号不能是模板。为了通过使用基类Message来创建模板样式的信号,让一个对象继承从QObject派生的多个模板类有什么缺点吗?此Message是信号的参数(以便信号和模板函数器具有基本版本(之后函数器将其转换为正确的类型T)。结构就像是这些模板类的袋子,继承所有这些模板类,以便随时向上转换到正确的模板类。

EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53857413

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档