"Inheriting"具有可变参数模板函数的类

"Inheriting" a class with variadic templated function

本文关键字:函数 变参 Inheriting 参数      更新时间:2023-10-16

我想编写一个可以操作不同类型的数据库(例如sqlite,postgres等)的数据库包装器,因此无论用户实际使用什么数据库,用户编写的代码都不会改变。

在我的脑海中,这需要一个抽象的基类,如下所示:

class database {
public:
    virtual bool query(const std::string &q) = 0;
    // Other stuff
};
class sqlite : public database {
public:
    bool query(const std::string &q) {
        // Implementation
    }
};

这看起来不错,但我正在使用可变参数模板来转义查询中的参数(我真的很喜欢这个想法,所以我想坚持下去!),所以不幸的是我的基类看起来像:

class database {
public:
    template <typename... Args>
    bool query(const std::string &q, const Args &... args) {
        // Implementation
    }
};

然而,这阻碍了创建抽象类,因为模板化函数不能是虚拟的。到目前为止,我唯一想到的是这个结构

template <class DatabaseType>
class database {
public:
    template <typename... Args>
    bool query(const std::string &q, const Args &... args) {
        return database_.query(q, args...);
    }
private:
    DatabaseType database_;
};

虽然这似乎有效,但对于所有只调用同名database_函数之外什么都不做的包装器,对我来说它看起来不是一个很好的风格。这是这里选择的设计模式,还是有更干净或更惯用的方式?

您可以从参数中生成一个查询对象query函数,并将其传递给虚拟query_impl函数。

[...]有没有更干净,或更惯用的方式

您可能需要查找 CRTP 以实现模板的多态行为。

template <class concrete_db> 
struct abstract_db { 
    template <typename... Args>
    void query(std::string const& q, Args const&... args) { 
        static_cast<concrete_db *>(this)->query(q, args...);
    }
};
struct postgres_db : abstract_db<postgres_db> {
    template <typename... Args>
    void query(std::string const& q, Args const&... args) { 
         // do something
    }
};