问题描述
假设有一个使用Qt的项目,并且依赖于新版Qt中的功能(例如,添加的类成员).该项目应使用Qt的系统"/发行版构建,该版本可能比项目所依赖的版本更早.
Suppose that there is a project that uses Qt, and depends on the features (e.g. added class members) present in a new version of Qt. The project is meant to be built with a "system"/distribution version of Qt that may be older than the version the project depends on.
幼稚的方法导致预处理器陷入困境:
The naive approach results in the preprocessor hell:
void Class::foo() {
#if QT_VERSION >= QT_VERSION_CHECK(...)
QClass::newFangled();
#else
QClass::oldFangled1();
blurble();
#endif
}
在使用该功能时,是否有一种更清洁的方法不依赖预处理程序宏? IE.我们不想要:
Is there a cleaner approach that won't depend on preprocessor macros at the point of use of the feature? I.e. we do not want:
// 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导入该名称空间中的类/函数,而无需进行任何更改,也可以将其作为自定义的类/函数,以向后移植所需的功能.
A workable approach is to use a given class or global function in a custom namespace. The class/function in that namespace can be imported from Qt without changes, or be the custom one that backports the needed features.
以下代码可识别Qt-namespace:它将与命名空间的Qt构建一起使用.
The code below is Qt-namespace-aware: it will work with a namespaced Qt build.
在使用时,可以在compat
名称空间(即
At the point of use, the backported functionality (global functions and classes) are accessed in the compat
namespace, i.e.
void test() {
...
qDebug() << compat::qEnvironmentVariableIntValue("RUNMODE");
compat::QTimer::singleShot(1000, object, []{ ... });
}
请注意,将具有默认参数的函数/方法添加到compat
命名空间时,默认参数仅在C ++ 17和更高版本中传播.否则,我们必须通过定义转发功能/方法来自己处理它们.
Note that when adding functions/methods with default arguments to the compat
namespace, the default arguments are propagated only in C++17 and later. Otherwise, we have to handle them ourselves by defining forwarding functions/methods.
假设我们要从Qt 5.5向后移植qEnvironmentVariableIntValue
:
Suppose that we want to backport qEnvironmentVariableIntValue
from Qt 5.5:
// 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)
:
Backporting into a class
Suppose that we want to backport Qt 5.4's QTimer::singleShot(int, QObject*, Functor)
, as motivated by 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
这篇关于如何在Qt中向后移植功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!