I'm using Mysql 5.6 with Qt5 and creating a class to encapsulate a database connection.
When I try to create an object in the main with dbConnect conn = new dbConnect("localhost", "test1","test","user"); I get and error telling me I need a conversion from dbConnect* to a non-scalar type.
Reading other posts I've seen this could be due to the type of inicialization I'm trying because it's not a good practice in C++ and should be something like dbConnect conn("localhost", "test1","test","user"); but, changing it like that, instead of getting the conversion error I get now a no matching function for call to QSqlDatabase::setHosTname(std::string&) and same with the other methods needed for connecting such as setDatabaseName, setUserName and setPassword
Could it be because of the std::string I'm using?
Or how should I create the object?
This is m y header db.h:
#ifndef DB
#define DB
#include <QSqlDatabase>
#include <string>
class dbConnect:QSqlDatabase
{
public:
dbConnect(std::string host, std::string name,std::string user, std::string pass);
bool createConnection(std::string host, std::string name,std::string user, std::string pass);
private:
QSqlDatabase dbObject;
};
#endif // DB_
Next here it is its implementation db.cpp:
#include<QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
class dbConnect:QSqlDatabase
{
private:
QSqlDatabase dbObject;
public:
dbConnect(std::string host, std::string name,std::string user, std::string pass)
{
if(createConnection(host, name, user, pass))
{
QMessageBox::information(0,"Connection Status","Connection established with database");
}
else
{
QMessageBox::critical(0,QObject::tr("Error connecting to database"),dbObject.lastError().text());
}
}
bool createConnection(std::string host, std::string name,std::string user, std::string pass)
{
dbObject = QSqlDatabase::addDatabase("QMYSQL");
dbObject.setHostName(host);
dbObject.setDatabaseName(name);
dbObject.setUserName(user);
dbObject.setPassword(pass);
if(!dbObject.open())
{
return false;
}
else
{
return true;
}
}
};
UPDATE
Took #gengisdave and #R Sahu solutions and now I'm trying to create an object in the main. If I try dbConnect conn(); it works fine even if the constructor takes for paremeter but, if I trye dbConnect conn("localhost","test1","test","user"); compiler gives me an error of undefined reference to dbConnect::dbConnect(std::string,std::string,std::string,std::string).
When you use:
dbConnect conn = new dbConnect("localhost", "test1","test","user");
the RHS is of type dbConnect* while the LHS is of type dbConnect. That is not correct. The compiler cannot take a pointer and assign it to an object.
You can use:
dbConnect* connPtr = new dbConnect("localhost", "test1","test","user");
or
dbConnect conn("localhost", "test1","test","user");
Other problems
bool createConnection(std::string host, std::string name,std::string user, std::string pass)
{
dbObject = QSqlDatabase::addDatabase("QMYSQL");
dbObject.setHostName(host);
dbObject.setDatabaseName(name);
dbObject.setUserName(user);
dbObject.setPassword(pass);
if(!dbObject.open())
{
return false;
}
else
{
return true;
}
}
is not right. You probably need:
bool createConnection(std::string host, std::string name,std::string user, std::string pass)
{
// Since this class is derived from QSqlDatabase,
// you can use:
this->addDatabase("QMYSQL");
this->setHostName(QString::fromStdString(host));
this->setDatabaseName(QString::fromStdString(name));
this->setUserName(QString::fromStdString(user));
this->setPassword(QString::fromStdString(pass));
if(!this->open())
{
return false;
}
else
{
return true;
}
}
Also, remove the member variable
QSqlDatabase dbObject;
You don't need it since the class is already derived from QSqlDatabase. You'll need to use that only if you don't derive from QSqlDatabase
QSQlDatabase::setHostName requires a parameter of type QString, while you provide a std::string; the same with the next 3 lines
you can change that lines to
this->setHostName(QString::fromStdString(host));
this->setDatabaseName(QString::fromStdString(name));
this->setUserName(QString::fromStdString(user));
this->setPassword(QString::fromStdString(pass));
EDIT: it works fine
main.cpp
#include <QApplication>
#include "db.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
dbConnect connection("localhost", "test1", "test", "user");
dbConnect *conn = new dbConnect("localhost", "test1", "test", "user");
}
db.cpp
#include <QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
#include "db.h"
dbConnect::dbConnect(std::string host, std::string name,std::string user, std::string pass)
{
if ( createConnection(host, name, user, pass) )
QMessageBox::information(0, "Connection Status", "Connection established with database");
else
QMessageBox::critical(0,QObject::tr("Error connecting to database"),dbObject.lastError().text());
}
bool dbConnect::createConnection(std::string host, std::string name,std::string user, std::string pass)
{
this->dbObject = QSqlDatabase::addDatabase("QMYSQL");
this->dbObject.setHostName(QString("localhost"));
this->dbObject.setDatabaseName(QString("test.txt"));
this->dbObject.setUserName(QString("test"));
this->dbObject.setPassword(QString("test"));
return this->dbObject.open();
}
db.h
#ifndef DB_H
#define DB_H
#include <QSqlDatabase>
#include <string>
class dbConnect:QSqlDatabase
{
public:
dbConnect(std::string host, std::string name,std::string user, std::string pass);
bool createConnection(std::string host, std::string name,std::string user, std::string pass);
private:
QSqlDatabase dbObject;
};
#endif
compiled with: gcc db.cpp main.cpp -I/usr/include/qt5/QtSql -I/usr/include/qt5/QtWidgets -I/usr/include/qt5 -fPIC -o main -lstdc++ -lQt5Sql -lQt5Core -lQt5Widgets
Related
I've running Mosquitto on my RPI4. But right know I only can set static callback functions. Is there a way to use class members?
I've tried to use std::bind to pass a class member function as callback:
main.cpp
#include <stdio.h>
#include <mosquitto.h>
#include "mqtt.h"
#include <string>
int main(int argc, char **argv)
{
MqttConnector * mqtt = new MqttConnector("piClient", "send", "rc", 1883, "localhost", 60);
mqtt->startClient();
return 0;
}
mqtt.h (only important parts
#include <mosquitto.h>
#include <string>
#include <stdio.h>
class MqttConnector
{
public:
MqttConnector(std::string id,
std::string sendTopic,
std::string receiveTopic,
int port,
std::string host,
int keepalive);
~MqttConnector();
void startClient();
private:
void messageCallback(struct mosquitto *mosq,
void *userdata,
const struct mosquitto_message *message);
struct mosquitto *mosqClient = NULL;
int keepalive;
int port;
std::string id;
std::string host;
std::string sendTopic;
std::string receiveTopic;
};
mqtt.cpp
#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>
using namespace std::placeholders;
MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{
mosquitto_lib_init();
mosqClient = mosquitto_new(NULL, true, NULL);
if(!mosqClient){
fprintf(stderr, "Error: Out of memory.\n");
}
this->keepalive = keepalive;
this->id = id;
this->host = host;
this->port = port;
this->sendTopic = sendTopic;
this->receiveTopic = receiveTopic;
}
MqttConnector::~MqttConnector()
{
mosquitto_destroy(mosqClient);
mosquitto_lib_cleanup();
}
void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
// I want to access class members like sendTopic / receiveTopic here
}
void MqttConnector::startClient()
{
// try to bind class members function
mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));
//other stuff
}
This gives me the following error while compiling:
cannot convert 'std::_Bind_helper<false, void (MqttConnector::*)(mosquitto*, void*, const mosquitto_message*), MqttConnector*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type' {aka 'std::_Bind<void (MqttConnector::*(MqttConnector*, std::_Placeholder<1>, std::_Placeholder<2>, std::_Placeholder<3>))(mosquitto*, void*, const mosquitto_message*)>'} to 'void (*)(mosquitto*, void*, const mosquitto_message*)'
83 | mosquitto_message_callback_set(mosqClient, std::bind(&MqttConnector::messageCallback, this, _1, _2, _3));
Why doesn't it work?
Thanks!
This is a problem of using C-api from C++. What is the difference between a member function and a free function? When you provide a pointer to a member function a pointer to the class object is implicitly passed as the first parameter. Since C-api doesn't do that, but the problem is well known, the solution was introduced and it is called passing a context. Usually it is done through a void pointer. Functions that register callbacks usually take the pointer to the free function and a pointer to context. Then this pointer will be passed as one of the callback parameters.
In mosquitto case this context pointer is passed beforehand at the creation of a mosquitto object with mosquitto_new.
In order to make the callback function behave like a C function, we declare it static.
Inside the callback function we use static_cast to cast the void pointer to the object that we have provided.
mqtt.h
#include <mosquitto.h>
#include <string>
#include <stdio.h>
class MqttConnector
{
public:
MqttConnector(std::string id,
std::string sendTopic,
std::string receiveTopic,
int port,
std::string host,
int keepalive);
~MqttConnector();
void startClient();
private:
// make this function static
---->
static void messageCallback(struct mosquitto *mosq,
void *userdata,
const struct mosquitto_message *message);
struct mosquitto *mosqClient = NULL;
int keepalive;
int port;
std::string id;
std::string host;
std::string sendTopic;
std::string receiveTopic;
};
mqtt.cpp
#include "mqtt.h"
#include <stdio.h>
#include <string>
#include <string.h>
#include <mosquitto.h>
#include <functional>
using namespace std::placeholders;
MqttConnector::MqttConnector(std::string id, std::string sendTopic, std::string receiveTopic, int port, std::string host, int keepalive)
{
mosquitto_lib_init();
// provide apointer to this as user data
mosqClient = mosquitto_new(NULL, true, this);
---->
if(!mosqClient){
fprintf(stderr, "Error: Out of memory.\n");
}
this->keepalive = keepalive;
this->id = id;
this->host = host;
this->port = port;
this->sendTopic = sendTopic;
this->receiveTopic = receiveTopic;
}
MqttConnector::~MqttConnector()
{
mosquitto_destroy(mosqClient);
mosquitto_lib_cleanup();
}
void MqttConnector::messageCallback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message)
{
// Use static cast to get pointer to your class object from userdata
MqttConnector *connector = static_cast<MqttConnector>(userdata);
connector->sendTopic;
}
void MqttConnector::startClient()
{
// static callback
mosquitto_message_callback_set(mosqClient, &MqttConnector::messageCallback);
// lambda callback
// beware, you can't use capture here
mosquitto_message_callback_set(&m, [/*no capture possible*/] (struct mosquitto *, void *userdata, const struct mosquitto_message *)
{
MqttConnector *connector = static_cast<MqttConnector>(userdata);
connector->sendTopic;
});
}
I'm working on a simple wrapper for a IPC lib we are using.
I want to convert the events from this lib to calls on Qt slots.
Right now i have something like this:
void Caller::registerCallback(int id, QObject* reciever, const char* member)
{
_callbackMap[id] = std::make_pair(reciever, QString(member));
}
bool Caller::call(const SomeData data)
{
auto reciever = _callbackMap.value(data.id);
return QMetaObject::invokeMethod(reciever.first, reciever.second.toLocal8Bit(), Qt::QueuedConnection,
QGenericReturnArgument(),
Q_ARG(SomeData, data));
}
void Receiver::someCallback(SomeData data)
{
qDebug() << data.str;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Caller caller;
Receiver reciever;
caller.registerCallback(1, &reciever, "someCallback");
caller.call(SomeData({ "Hi", 1 }));
return a.exec();
}
struct SomeData {
QString str;
int id;
}; Q_DECLARE_METATYPE(SomeData);
This works quite well. But I don't like to register the callbacks as strings. I would prefer a compile time checking with a syntax like this:
caller.registerCallback(1, &reciever, &Reciever::someCallback);
I am aware of this implementation.
The slots I want to register always have exactly one argument and no return value.
I already found this request what could solve my problem but unfortunately this was never implemented.
Also this question doesn't help me as I'm not able to patch the moc we are using.
So is this really not possible with all the meta magic Qt is using?
EDIT:
I found a solution that works also when the Caller dose not know about the Receiver (what is actually what I need):
//Caller.h
class Caller : public QObject
{
Q_OBJECT
public:
Caller(QObject *parent = nullptr);
~Caller();
//void registerCallback(int id, QObject* reciever, const char *member);
template < class R, typename Func >
void inline registerCallback(int id, R reciever, Func callback)
{
using std::placeholders::_1;
registerCallbackImpl(id, reciever, std::bind(callback, reciever, _1));
};
bool call(const SomeData);
private:
QMap<int, std::pair<QObject *, std::function<void(SomeData)>> > _callbackMap;
void registerCallbackImpl(int id, QObject* reciever, std::function<void(SomeData)> callback);
};
//Caller.cpp
void Caller::registerCallbackImpl(int id, QObject* reciever, std::function<void(SomeData)> callback)
{
_callbackMap[id] = std::make_pair(reciever, callback);
}
bool Caller::call(const SomeData data)
{
auto reciever = _callbackMap.value(data.id).first;
auto fn = _callbackMap.value(data.id).second;
QMetaObject::invokeMethod(reciever, [reciever, fn, data]() {
std::invoke(fn, data);
fn(data);
}, Qt::QueuedConnection);
return true;
}
//main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Caller caller;
Receiver reciever;
using std::placeholders::_1;
caller.registerCallback(2, &reciever, &Receiver::someCallback);
caller.call(SomeData({ "Hi2", 2 }));
return a.exec();
}
This soulution relies upon std::invoke and lambda.
Variant 1: use std::invoke directly instead of QMetaObject::invoke
Variant 2: use std::invoke inside a lambda, which is passed to QMetaObject::invoke
Variant 3: use MACRO instead of std::invoke in variant 2.
If you use QMetaObject::invoke you've got an option to choose connection type - Direct or Queued. In variant 1 the call is invoked immediately like in direct connection.
receiver.h
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
#include <QDebug>
struct SomeData {
QString str;
int id;
};
//Q_DECLARE_METATYPE(SomeData);
class Receiver : public QObject
{
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr) : QObject(parent) {}
void doSmth(SomeData data) {
qDebug() << data.str;
}
signals:
};
#endif // RECEIVER_H
caller.h
#ifndef CALLER_H
#define CALLER_H
#include <QObject>
#include <QMap>
#include <utility>
#include <map>
#include "receiver.h"
#define CALL_MEMBER_FN(object,ptrToMember) ((object)->*(ptrToMember))
typedef void (Receiver::*callback)(SomeData);
class Caller : public QObject
{
Q_OBJECT
public:
explicit Caller(QObject *parent = nullptr) : QObject(parent) { }
void registerCallback(int id, Receiver* receiver, callback c)
{
auto pair = std::make_pair(receiver, c);
_callbackMap.emplace(id, pair);
}
bool call(const SomeData data)
{
auto &receiver = _callbackMap.at(data.id);
return QMetaObject::invokeMethod(receiver.first, [data, receiver] () {
// method 1
std::invoke(receiver.second, receiver.first, data);
// method 2 (better not to use a MACRO)
CALL_MEMBER_FN(receiver.first, receiver.second)(data);
}, Qt::QueuedConnection);
}
bool call_invoke(const SomeData data)
{
auto &receiver = _callbackMap.at(data.id);
std::invoke(receiver.second, receiver.first, data);
return true;
}
signals:
private:
std::map<int,std::pair<Receiver*,callback>> _callbackMap;
};
#endif // CALLER_H
main.cpp
#include <QCoreApplication>
#include "receiver.h"
#include "caller.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Caller caller;
Receiver reciever;
caller.registerCallback(1, &reciever, &Receiver::doSmth);
caller.registerCallback(2, &reciever, &Receiver::doSmth);
caller.call(SomeData({ "Hi", 1 }));
caller.call_invoke(SomeData({ "Hi2", 2 }));
return a.exec();
}
An alternative approach might be to use a suitable std::function to capture the callback and then make use of QTimer::singleShot with a zero timeout to invoke the callback in the correct context.
struct SomeData {
QString str;
int id;
};
class Caller {
public:
using task = std::function<void(SomeData)>;
void registerCallback (int id, QObject *receiver, task t)
{
_callbackMap[id] = std::make_pair(receiver, t);
}
bool call (SomeData data)
{
auto receiver = _callbackMap.value(data.id);
QTimer::singleShot(0, receiver.first, [=](){ receiver.second(data); });
return true;
}
private:
QMap<int, std::pair<QObject *, task>> _callbackMap;
};
class Receiver: public QObject {
public:
void someCallback (SomeData data)
{
qDebug() << data.str;
}
};
Then use as...
Caller caller;
Receiver receiver;
caller.registerCallback(1, &receiver, [&](SomeData d){ receiver.someCallback(d); });
caller.call(SomeData({ "Hi", 1 }));
I wanna create abstract Db class and implement Pg (postgresql) by inheriting from Db:
Db.h:
template <class T>
class Db
{
public:
Db(std::string, std::string, std::string, std::string);
virtual ~Db();
protected:
T* getConnection();
std::string getHost();
std::string getUsername();
std::string getDatabase();
std::string getPassword();
virtual std::string getConnectionString()=0;
private:
T* connection;
std::string host;
std::string username;
std::string database;
std::string password;
};
Db.cpp:
#include "Db.h"
using namespace std;
template <class T>
Db<T>::Db(string iHost, string iUsername, string iDatabase, string iPassword)
: host(iHost), username(iUsername), database(iDatabase), password(iPassword) {
T* conn(getConnectionString());
connection = conn;
}
template <class T>
T* Db<T>::getConnection() {
return connection;
}
... getters
Pg.h:
#include "../Db.h"
template <class T>
class Pg : public Db<T> {
public:
virtual std::string getConnectionString();
};
Pg.cpp:
#include "Pg.h"
template <class T>
std::string Pg<T>::getConnectionString() {
return "host=" + this->getHost() + " user=" + this->getUsername()
+ " password=" + this->getPassword() + " dbname=" + this->getDatabase();
}
main.cpp:
#include <iostream>
#include <pqxx/connection>
#include <pqxx/transaction>
#include "lib/db/pg/Pg.h"
using namespace std;
int main () {
string host = "localhost";
string username = "username";
string database = "db";
string password = "root";
try {
Pg<pqxx::connection> *db(host, username, database, password);
} catch (pqxx::broken_connection) {
cout << "Failed to establish connection." << endl;
}
return 0;
}
Sorry for long implementation. After compiling with g++ I get an error:
main.cpp: In function ‘int main()’:
main.cpp:15:62: error: expression list treated as compound expression in initializer [-fpermissive]
Pg<pqxx::connection> *db(host, username, database, password);
^
main.cpp:15:62: error: cannot convert ‘std::string {aka std::basic_string<char>}’ to ‘Pg<pqxx::basic_connection<pqxx::connect_direct> >*’ in initialization
I don't know if it is a good idea in the end, because my first version with only main() function looked more compact. I just try to hide connection details somewhere, such as connection string.
In main(), your db variable is declared as a pointer. You cannot pass constructor parameters to a pointer like you are doing.
You need to either:
drop the * from the declaration:
Pg<pqxx::connection> db(host, username, database, password);
keep the * and use new to construct the object:
Pg<pqxx::connection> *db = new Pg<pqxx::connection>(host, username, database, password);
...
delete db;
I am newbie in Qt and learning to handle how QHash works. On working with this example I dont understand why this throws me an error. I may miss something, but please guide me to learn this.
main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QHash<QString,Person> hash;
QString key="1";
Person p;
p.name = name;
p.number = an;
hash.insert(key,p);
return a.exec();
}
person.h
class Person
{
public:
Person();
Person(QString name,QString num);
bool operator==(const Person & other) const; //== overloading to assign in QHash
QString name,number;
};
person.cpp
Person::Person()
{
}
Person::Person(QString name, QString num)
{
this->name=name;
this->number=num;
}
bool Person::operator==(const Person & other) const
{
bool state;
if (name == other.name )
state = true;
else
state = false;
return state;
}
and the error is:-'qHash':none of the 17 overloads could convert all the argument type.I knw im missing something.Please guide me.
You need the global qHash() function.
A QHash's key type has additional requirements other than being an
assignable data type: it must provide operator==(), and there must
also be a qHash() function in the type's namespace that returns a hash
value for an argument of the key's type.
See this for more info about that.
The code you've provided is not complete and not compilable - e.g. The symbol name is not found, no includes.
The op == is not required when you use the class as value. The only one requirement for value-classes - a default constructor.
I think you problem was something else. If you provided the complete code and the complete list of errors I could tell you what exactly.
Below you'll find the working version of you code-snippet. (For simplicity, everything in one file)
main.cpp
#include <QApplication>
#include <QHash>
#include <QString>
class Person
{
public:
Person(QString name=QString::null,QString num=QString::null);
QString name,number;
};
Person::Person(QString _name, QString _num)
:name(_name),number(_num)
{
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QHash<QString,Person> hash;
QString key="1";
Person p("Orhan Kemal", "1914");
hash.insert(key,p);
return a.exec();
}
Regards,
Valentin
EDIT:
Initialized members not in body
I wrote c++ class to connect to mysql database:
hpp file
#include <vector>
#include <string>
#include "mysql/mysql.h"
#ifndef _DATA
#define _DATA
class Database {
public:
string host;
string user;
string pwd;
string db;
MYSQL * connection;
MYSQL_RES *result;
MYSQL_ROW row;
Database(const string & host,
const string & user,
const string & pwd,
const string & db);
int createMysqlConnection();
};
#endif
cpp file
#include "Database.hpp"
Database::Database(const string & host,
const string & user,
const string & pwd,
const string & db) :
mysqlHost(host),
mysqlUser(user),
mysqlPassword(pwd),
mysqlDBName(db)
{}
int Database::createMysqlConnection(){
MYSQL * connection;
connection = mysql_init(NULL);
if(!mysql_real_connect(connection, mysqlHost.c_str(), mysqlUser.c_str(),
mysqlPassword.c_str(), mysqlDBName.c_str(),
0, NULL, 0)){
fprintf(stderr, "Connection to database failed: %s\n",
mysql_error(connection));
return EXIT_FAILURE;
}
cout << "connected to mysql" << endl;
};
When I'm trying to access connection variable from the main function or from a different class I always get an error like variable 'connection is not declared in this scope. I tried to use friend classes or inheritance to point to connection variable but it didn't work. I think I'm doing something wrong in my syntax.
Here is an example of how I try to point to this variable from different class:
Class risk: public Database {
public:
vector<sting> parameter;
Datasabse.connection;
etc....
}
to solve this problem i had to define MYSQL connection in class constructor. here is a code sample:
class1.hpp
***headers***
class Flight {
public:
Flight(MYSQL * connection);
MYSQL * c;
MYSQL_RES * res;
etc...
Class1.cpp
***headers***
Flight::Flight (MYSQL* connection)
{
c = connection;
};
etc...
main.cpp
***headers***
int main (int argc, char *argv[]) {
Database db(localhost, user, etc..);
db.createMysqlConnection;
Flight fl(db.connection);
fl.GetIDs();
etc...
MYSQL * connection;
declares the connection variable as local to the constructor only. You must move it to the class definition in order to make it available somehow. Alternatively, make a connect method in your Database object to explicitely create a new connection adlib. You will have to mirror it with a close method.
Yet another option is to create a dedicated class Connection for connections, which would:
be constructed with a MYSQL *,
be created by the connect method of Database as suggested above; the Database class would act as a Connection factory,
sports all the necessary methods to handle it,
and would call mysql_close in its destructor, to ensure proper termination of the underlying connection.
For instance:
class Connection {
protected:
MYSQL *connection;
public:
Connection(MYSQL *c): connection(c){}
virtual ~Connection() { mysql_close(connection); }
MYSQL_STMT * prepareQuery(const string &query) {
return mysql_prepare(connection, query.c_str(), query.length());
}
// other methods
};
The problem with this approach is that you quickly feel compeled to wrap all the API primitives with classes.