我有一个接口基类:
class BaseDicModel {
public:
virtual ~BaseDicModel() {}
virtual QString text() const = 0;
virtual int id() const = 0;
virtual void parseQuery(QSqlQuery *q) = 0;
virtual QJsonObject toJson() = 0;
};
以及一个模板函数,它应该执行SQL查询并返回依赖于模板类的字典。
template <class T>
/**
* @brief Loading dictionary from database
* @param sqlQuery sql query to execute
* @return Dictionary of type T
* !!! T MUST BE DERIVED FROM BaseDicModel !!!
*/
static QList<T *>
getDictionary(QString sqlQuery) {
QList<T *> result;
QString conName = "regionConnection";
{
QSqlDatabase conn = getConnectionV2(
conName, ConfigService::getInstance()->get_db_connection());
// int ret = -1;
bool bOpen = false;
if (!conn.isOpen()) {
if (!conn.open()) {
qWarning() << "Error while open db";
return result;
}
bOpen = true;
}
QSqlQuery *query = new QSqlQuery(conn);
query->prepare(sqlQuery);
if (query->exec()) {
while (query->next()) {
T *row = new T();
row->parseQuery(query);
result.append(row);
}
} else {
qWarning() << "Error while exec query:" << query->lastError().text();
}
delete query;
if (bOpen) { conn.close(); }
}
QSqlDatabase::removeDatabase(conName);
return result;
}
};
它工作得很好,但我有一个问题:template class现在可以是ANYclass,我想得到的是仅用于BaseDicModel派生类的template。类似这样的伪代码:
template<class T implements BaseDicModel>
你能给予我一些提示如何使它工作吗?这个问题一定很傻,但我似乎不明白。谢谢
1条答案
按热度按时间bbmckpt71#
就我个人而言,我只会依赖于鸭子类型,并不关心,也许除了重命名T到你的上下文中有意义的东西,例如。DicModel。
在C++20之前,它有点难看,但可以通过添加第二个模板参数来完成。我更喜欢一个非类型的,因为它提供了稍微好一点的保护,防止智取检查,但一个类型的也应该这样做。
我猜
is_base_of
和enable_if
将是主要的主力,还有is_same
。所以,从上到下,首先应该添加额外的参数,我选择了一个指向void的指针。非类型参数背后的逻辑是,如果试图手动指定该参数,则无论它如何,检查都将应用:
typename std::enable_if<?????>::type* = nullptr
1.里面的条件检查T是否是某个基数,因此
std::is_base_of<Base, T>::value
1.可选地,可以添加第二个检查以验证T是否不是基类型本身
&& !std::is_same<T, Base>::value
1.所以把它们放在一起:
template <typename T, typename std::enable_if<std::is_base_of<Base, T>::value && !std::is_same<T, Base>::value>::type* = nullptr>
Demo