c++ 如何设置预期的模板参数基类型

jhkqcmku  于 2023-06-07  发布在  其他
关注(0)|答案(1)|浏览(101)

我有一个接口基类:

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>

你能给予我一些提示如何使它工作吗?这个问题一定很傻,但我似乎不明白。谢谢

bbmckpt7

bbmckpt71#

就我个人而言,我只会依赖于鸭子类型,并不关心,也许除了重命名T到你的上下文中有意义的东西,例如。DicModel。
在C++20之前,它有点难看,但可以通过添加第二个模板参数来完成。我更喜欢一个非类型的,因为它提供了稍微好一点的保护,防止智取检查,但一个类型的也应该这样做。
我猜is_base_ofenable_if将是主要的主力,还有is_same
所以,从上到下,首先应该添加额外的参数,我选择了一个指向void的指针。非类型参数背后的逻辑是,如果试图手动指定该参数,则无论它如何,检查都将应用:

  1. 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>
#include <type_traits>

struct Base
{
    virtual ~Base() = default;
};

struct DerivedPublic : Base{};

class DerivedPrivate : Base{};

struct DerivedFurther : DerivedPrivate{};

// derived + base
template <typename T, typename std::enable_if<std::is_base_of<Base, T>::value>::type* = nullptr>
// derived only
// template <typename T, typename std::enable_if<std::is_base_of<Base, T>::value && !std::is_same<T, Base>::value>::type* = nullptr>
struct S{};

int main(int, char*[])
{
    S<Base> sb;
    S<DerivedPublic> sdpub;
    S<DerivedPrivate> sdprv;
    S<DerivedFurther> sdf;
    // S<int> si;
}

Demo

相关问题