【问题标题】:How to backport functionality in Qt?如何在 Qt 中反向移植功能?
【发布时间】:2018-04-16 16:41:45
【问题描述】:

假设有一个项目使用 Qt,并且依赖于 Qt 新版本中的特性(例如添加的类成员)。该项目旨在使用 Qt 的“系统”/分发版本构建,该版本可能比项目所依赖的版本更旧。

天真的方法导致预处理器地狱:

void Class::foo() {
#if QT_VERSION >= QT_VERSION_CHECK(...)
  QClass::newFangled();
#else
  QClass::oldFangled1();
  blurble();
#endif
}

是否有更简洁的方法在使用该功能时不依赖于预处理器宏? IE。我们不想要:

// THIS IS BLAH
#if QT_VERSION >= QT_VERSION_CHECK(...)
#define QClass_newFangled QClass::newFangled
#else
#define QClass_newFangled [this]{ \
   QClass::oldFangled1(); \
   blurble(); \
}
#endif
void Class::foo() {
  QClass_newFangled();
}

【问题讨论】:

  • 您始终可以自己构建 Qt(无论您需要什么版本 - 前缀为“/opt/myapp/qt”),然后将您的应用与 那个 版本链接并成为完全独立于系统 Qt 版本。
  • @JesperJuhl 要求是使用系统版本 :) 当然,总是可以构建自定义 Qt 版本,但有时——尤其是开源项目——它可能会限制项目的可用性,或者只是为了向后移植一些功能而不必要地浪费了编译时间。

标签: c++ qt backport


【解决方案1】:

一种可行的方法是在自定义命名空间中使用给定的类或全局函数。该命名空间中的类/函数可以直接从 Qt 导入而无需更改,也可以是支持所需功能的自定义类/函数。

下面的代码是 Qt-namespace-aware 的:它将与命名空间的 Qt 构建一起工作。

在使用时,在 compat 命名空间中访问向后移植的功能(全局函数和类),即

void test() {
  ...
  qDebug() << compat::qEnvironmentVariableIntValue("RUNMODE");
  compat::QTimer::singleShot(1000, object, []{ ... });
}

请注意,将具有默认参数的函数/方法添加到 compat 命名空间时,默认参数仅在 C++17 及更高版本中传播。否则,我们必须自己定义转发函数/方法来处理它们。

向后移植一个全局函数

假设我们想从 Qt 5.5 向后移植 qEnvironmentVariableIntValue

// INTERFACE

namespace compat {
#if QT_VERSION >= QT_VERSION_CHECK(5,5,0)
#if __cplusplus >= 201703L
using QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue); // C++17
#else
int inline qEnvironmentVariableIntValue(const char *varName, bool *ok = {}) {
  return QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)(varName, ok);
}
#endif
#else
int qEnvironmentVariableIntValue(const char *varName, bool *ok = {});
#endif
} // compat
// IMPLEMENTATION

namespace compat {
#if QT_VERSION < QT_VERSION_CHECK(5,5,0)
using QT_PREPEND_NAMESPACE(qgetenv); // C++17
int qEnvironmentVariableIntValue(const char *varName, bool *ok) {
  return qgetenv(varName).toInt(ok, 0);
}
#endif // Qt<5.5
} // compat

向后移植到一个类中

假设我们想要反向移植 Qt 5.4 的 QTimer::singleShot(int, QObject*, Functor),受 this answer 的激励:

// INTERFACE

namespace compat {
#if QT_VERSION >= QT_VERSION_CHECK(5,4,0)

using QT_PREPEND_NAMESPACE(QTimer);

#else

using Q_QTimer = QT_PREPEND_NAMESPACE(QTimer);
class QTimer : public Q_QTimer {
  Q_OBJECT
public:
  #if __cplusplus >= 201703L
  using Q_QTimer::Q_QTimer; // C++17
  #else
  QTimer(QObject *parent = {}) : Q_QTimer(parent) {}
  #endif
  template <class Functor> static void singleShot(int, QObject *, Functor &&);
};

template <class Functor>
void QTimer::singleShot(int msec, QObject *context, Functor &&fun) {
  ...
}

#endif
} // compat

【讨论】:

    猜你喜欢
    • 2012-08-21
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 2013-03-17
    • 2021-04-19
    • 1970-01-01
    • 2011-07-14
    • 2011-06-29
    相关资源
    最近更新 更多