C++ 如何在Qt中实现后端口功能?

C++ 如何在Qt中实现后端口功能?,c++,qt,backport,C++,Qt,Backport,假设有一个使用Qt的项目,它取决于Qt新版本中的特性(例如添加的类成员)。该项目旨在使用Qt的“系统”/“分发版本”构建,该版本可能比项目所依赖的版本旧 天真的方法会导致预处理器地狱: void Class::foo() { #if QT_VERSION >= QT_VERSION_CHECK(...) QClass::newFangled(); #else QClass::oldFangled1(); blurble(); #endif } 是否有一种更干净的方法在使用该功

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

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

void Class::foo() {
#if QT_VERSION >= QT_VERSION_CHECK(...)
  QClass::newFangled();
#else
  QClass::oldFangled1();
  blurble();
#endif
}
是否有一种更干净的方法在使用该功能时不依赖于预处理器宏?即,我们不希望:

// 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导入而不做任何更改,也可以是后台移植所需特性的自定义类/函数

下面的代码是Qt名称空间感知的:它将与具有名称空间的Qt构建一起工作

在使用点,后端口功能(全局函数和类)在
compat
名称空间中访问,即

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

您可以自己构建Qt(无论您需要什么版本-前缀为“/opt/myapp/Qt”),然后将您的应用程序与该版本链接,并完全独立于系统Qt版本。@JesperJuhl要求使用系统版本:)当然,您可以始终构建自定义Qt版本,但有时——特别是对于开源项目——它可能会限制项目的可用性,或者为了几个功能的后端口而不必要地增加编译时间。
// 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
// 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