使用宏来创建QObject派生类

cma*_*t85 5 c++ macros qt moc c-preprocessor

我试图简化(即摆脱样板代码的负载)创建QObject包装类,转发其他QObject派生类的属性访问.

从小处开始,我只是尝试使用一个属性:

// Sy_test.h - The wrapped class
class Sy_test : public QObject
{
    Q_OBJECT
    Q_PROPERTY( bool prop READ getProp WRITE setProp NOTIFY propChanged )

public:
    Sy_test( QObject* parent = nullptr ) :
        QObject{ parent },
        prop_{ false } {}

    bool getProp() const { return prop_; }

public slots:
    void setProp( bool value )
    {
        if ( value != prop_ ) {
            prop_ = value;
            emit propChanged( prop_ );
        }
    }

signals:
    void propChanged( bool value );

private:
    bool prop_;
};

// Sy_proxy.h - The wrapper generator
#define SY_PROXYPROPERTY( Type, Name, Getter, Setter, Notifier )\
private:\
    Q_PROPERTY( Type Name READ Getter WRITE Setter NOTIFY Notifier )\
\
public:\
    Type Getter() const { return target_->Getter(); }\
\
public slots:\
    void Setter( Type value ) { target_->Setter( value ); }\
\
signals:\
    void Notifier( Type value );\
\
private:\
    void setConnection()\
    {\
        connect( target_, &std::remove_pointer< decltype( target_ ) >::type::Notifier,\
                 this,    &std::remove_pointer< decltype( this    ) >::type::Notifier );\
    }

#define SY_PROXY( ProxyName, TargetType, Prop1 )\
class ProxyName : public QObject\
{\
    Q_OBJECT \
    Prop1 \
\
public:\
    ProxyName( TargetType* target ) :\
        target_{ target }\
    {\
        setConnection();\
    }\
\
    virtual ~ProxyName() {}\
\
private:\
    TargetType* target_;\
};

// This should create a Sy_test wrapper class called Sy_testProxy
SY_PROXY( Sy_testProxy,
          Sy_test,
          SY_PROXYPROPERTY( bool, prop, getProp, setProp, propChanged ) )
Run Code Online (Sandbox Code Playgroud)

所以SY_PROXY宏应该创建一个名为的类Sy_testProxy,它带有一个Sy_test::prop属性的副本,其实现仅转发请求/信号.

几乎可以.查看后预处理器输出(我使用的是g ++,即.ii文件),我可以看到Sy_testProxy该类是构建的,它与Sy_test类的形式相同.但是,我收到一个错误:

../CppTest/Sy_proxy.h:47: Error: NOTIFY signal 'propChanged' of property 'prop' does not exist in class Sy_testProxy.
make: *** [moc_Sy_proxy.cpp] Error 1
Run Code Online (Sandbox Code Playgroud)

所以它似乎moc无法解析我的宏魔法; 虽然我不确定SY_PROXY宏存在的位置(错误来自一个被调用的类Sy_testProxy),并且SY_PROXYPROPERTY必须也是有效的(因为moc必须从中读取Q_PROPERTY宏).谁能看到我出错的地方?

为了记录:我讨厌像其他人一样的宏,但由于moc对模板和QObject虚拟继承的厌恶,我已经开始使用它们了.之所以触发此调查,是因为我在一个单独的线程中执行了大量计算的实例集合,但它们驱动了QML表示.但是QML不允​​许连接/属性绑定到主线程之外的对象,所以我被迫创建生活在主线程中的代理对象.如果有人有更好的想法,我对他们很开放!

lee*_*mes 5

moc我不太喜欢宏。它可以在一定程度上扩展它们,但是当它们变得复杂¹时会失败。

您可以尝试将其替换signals:public:²(即,手动扩展signals宏),并通过Q_SIGNAL在函数声明的前面声明希望该函数成为信号。

更换

signals:\
    void Notifier( Type value );\
Run Code Online (Sandbox Code Playgroud)

public:\
    Q_SIGNAL void Notifier( Type value );\
Run Code Online (Sandbox Code Playgroud)

¹:关于复杂的定义...我不知道什么时候失败,但是过去我遇到了一些不同的问题。根据我的经验,就像signals您的示例一样,当宏主体包含另一个宏时,moc会出现问题。但这只是一个猜测-可能是moc失败的那种宏是另外一回事。

²:在Qt 5之前曾经是protected