Working on my SQL project at last.The concept is easy to use and integrate SQL into C++.    ThorsSQL::Connection    mysql(mysql://host, username, password, databaseName);    ThorsSQL::Statement     bigEarnerStat(mysql,                                           SELECT ID, Name, Salary FROM Employee WHERE Salary > % and Age < %                                          ThorsAnvil::SQL::Prepare);    // Bind variables to '%' in statement    // Then execute the SQL statement.    // Call function for every row returned.    bigEarnerStat.execute(Bind(1000000, 32), // parameter bound to % in statement.        // Function executed for each row returned.        // Parameters are matched against the SELECT in the statement.        // A bad type conversion will throw an exception.        [](u64 id, std::string const& name, int salary){            std::cout << name <<  is a fat cat earning $ << salary/100 << . << salary%100 << \n;        }    );Connection:Represents a single connection to the DB.The thing to note above is mysql://host. The concept being that these classes provide the framework that allows specific DB code to be plugged into (A MySQL variant will be coming to code review soon). So the Schema part of the URL string specifies the type of DB (and thus what specific plugin the code below uses (see ConnectionCreatorRegister)So the Connection object will defer all the DB specific work to the proxy member. This class handles all the generic code.ConnectionProxy:This DB specific code for a connection.ConnectionCreatorRegister:This allows a DB specific implementation to register itself as a viable alternative.Note: If you want to try compiling the code I suggest you check it out of the git repo and compile using the instructions there. But Saying that you can potentially compile it using only the source here just add a main().Connection.h#ifndef THORS_ANVIL_SQL_CONNECTION_H#define THORS_ANVIL_SQL_CONNECTION_H#include SQLUtil.h#include <string>#include <map>#include <memory>namespace ThorsAnvil{    namespace SQL    {        class Statement;        class StatementProxy;        class ConnectionProxy        {            public:                virtual ~ConnectionProxy()  = 0;                virtual std::unique_ptr<StatementProxy> createStatementProxy(std::string const& statement, StatementType type) = 0;        };        inline ConnectionProxy::~ConnectionProxy() {}        using ConnectionCreator= std::function<std::unique_ptr<ConnectionProxy>(std::string const& host, int port,                                                                        std::string const& username,                                                                        std::string const& password,                                                                        std::string const& database,                                                                        Options const& options)>;        class Connection        {            private:                static std::map<std::string, ConnectionCreator>&    getCreators();                friend class Statement;                std::unique_ptr<StatementProxy> createStatementProxy(std::string const& statement, StatementType type);                std::unique_ptr<ConnectionProxy>  proxy;            public:                Connection(std::string const& connection,                            std::string const& username,                            std::string const& password,                            std::string const& database,                            Options const& options = Options{});                static void registerConnectionType(std::string const& schema, ConnectionCreator creator);        };        template<typename T>        class ConnectionCreatorRegister        {            public:                ConnectionCreatorRegister(std::string const& schema)                {                    Connection::registerConnectionType(schema, [](std::string const& host, int port,                                                                std::string const& username,                                                                std::string const& password,                                                                std::string const& database,                                                                Options const& options)                    {                        return std::unique_ptr<ConnectionProxy>(new T(host, port , username, password, database, options));                    });                }        };    }} #endifConnection.cpp#include Connection.h#include Statement.h#include <cerrno>#include <cstdlib>using namespace ThorsAnvil::SQL;Connection::Connection(std::string const& connection,                       std::string const& username,                       std::string const& password,                       std::string const& database,                       Options const& options){    std::size_t     schemaEnd   = connection.find(':');    if (schemaEnd == std::string::npos || connection[schemaEnd + 1] != '/' || connection[schemaEnd + 2] != '/') {        throw std::runtime_error(Connection::Connection: Failed to find schema:  + connection);    }    bool        hasPort     = true;    std::size_t hostEnd     = connection.find(':', schemaEnd + 3);    if (hostEnd == std::string::npos) {        hasPort = false;        hostEnd = connection.size();    }    std::string schema      = connection.substr(0, schemaEnd);    std::string host        = connection.substr(schemaEnd + 3, hostEnd - schemaEnd - 3);    std::string port        = hasPort ? connection.substr(hostEnd + 1) : 0;    errno                   = 0;    char*       endPtr;    int         portNumber  = std::strtol(port.c_str(), &endPtr, 10);    auto        creator     = getCreators().find(schema);    if (host ==  || errno != 0 || *endPtr != '\0') {        throw std::runtime_error(Connection::Connection: Failed to parse connection:  + connection);    }    if (creator == getCreators().end()) {        throw std::runtime_error(Connection::Conection: Schema for unregister DB type:  + schema +  From:  + connection);    }    proxy   = creator->second(host, portNumber, username, password, database, options);}std::map<std::string, ConnectionCreator>& Connection::getCreators(){    static std::map<std::string, ConnectionCreator> creators;    return creators;}void Connection::registerConnectionType(std::string const& schema, ConnectionCreator creator){    getCreators().emplace(schema, creator);}std::unique_ptr<StatementProxy> Connection::createStatementProxy(std::string const& statement, StatementType type){    return proxy->createStatementProxy(statement, type);}test/ConnectionTest.cpp#include Connection.h#include Statement.h#include gtest/gtest.h#include test/MockMysql.hThorsAnvil::SQL::ConnectionCreatorRegister<MockMySQLConnection>   registerFakeMysql(mysql);TEST(ConnectionTest, Create){    using ThorsAnvil::SQL::Connection;    Connection     connection(mysql://127.0.0.1:69, root, testPassword, test);}TEST(ConnectionTest, CreateDefaultPort){    using ThorsAnvil::SQL::Connection;    Connection     connection(mysql://127.0.0.1, root, testPassword, test);}TEST(ConnectionTest, BadSchema){    using ThorsAnvil::SQL::Connection;    ASSERT_THROW(    Connection     connection(badschema://127.0.0.1:69, root, testPassword, test),    std::runtime_error    );}TEST(ConnectionTest, NoSchema){    using ThorsAnvil::SQL::Connection;    ASSERT_THROW(    Connection     connection(127.0.0.1:69, root, testPassword, test),    std::runtime_error    );}TEST(ConnectionTest, BadHost){    using ThorsAnvil::SQL::Connection;    ASSERT_THROW(    Connection     connection(mysql://:69, root, testPassword, test),    std::runtime_error    );}TEST(ConnectionTest, BadPort){    using ThorsAnvil::SQL::Connection;    ASSERT_THROW(    Connection     connection(mysql://127.0.0.1:XY, root, testPassword, test),    std::runtime_error    );}
C++ SQL wrapper/Connection
c++;sql;c++14;template meta programming
GCC now has SSO, with the ABI breaking backwards compatibility and all that. Which probably means you can pass them by value.