I want to write a database wrapper that can operate different types of databases (e.g. sqlite, postgres, etc.), so the code that users are writing does not change regardless of what database they actually are using.
In my head, this calls for an abstract base class like:
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
}
};
This looks good, but I am using variadic templates for escaping arguments inside queries (and I really like this idea, so I would want to hang on to it!), so unfortunately my base class rather looks like:
class database {
public:
template <typename... Args>
bool query(const std::string &q, const Args &... args) {
// Implementation
}
};
This stands in the way of creating an abstract class however, because templated functions cannot be virtual. The only thing I came up with so far is this construct
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_;
};
While this seems to work, with all the wrappers that do nothing but call the identically named database_ functions it does not look like a very good style to me. Is this the design pattern of choice here, or is there a cleaner, or more idiomatic way?
You can build a query object out of the arguments to the
queryfunction, and pass it to a virtualquery_implfunction.