如何改进一些可变参数包模板实现

问题描述

我设法创建了一个库来帮助我向 sqlLite 库发出请求,特别是那些与 BLOB 文件相关的请求。

问题来了是因为我觉得实现可以改进,但我没有足够的知识来实现​​它。对这两个问题的任何帮助:

  1. 可以使用 sql 语句作为 c-pure 字符串或 std::string 调用某些函数。他们两个最终调用一个函数最终实现。如果我尝试删除函数声明和调用的“_”(请参阅​​源代码),则问题来自对模板函数的明确调用。我知道这是一个小问题,但我想知道是否有任何方法可以实现它。

  2. 我尝试对使用文件数据库中加载 BLOB 的请求以及不使用 BLOBS 的请求使用相同的代码。区别在于第一个使用文件流作为参数,第二个没有任何流参数。 sqlLite 强制调用特定函数来执行 sql 语句,所以我需要使用“if consexpr...”条件子句将 0 个参数的情况与 1 个或多个流参数的情况分开。

代码在前面:

#include <string>
#include <sstream>
#include <utility>

class sqlite3 {};
class sqlite3_stmt {};
void sqlite3_step(sqlite3_stmt*) {}
sqlite3* db;

//Auxiliary BLOB functions
template<typename T>
bool sqlite3_blob(sqlite3_stmt*,const T& data,int col);

template<>
bool sqlite3_blob<std::ostringstream>(sqlite3_stmt* statement,const std::ostringstream& data,int col)
{
    //std::string buffer{ data.str() };
    return true;
}

//sqlite3 automatization request
template<typename... Args,std::size_t... Is>
constexpr bool sqlite3_request_(sqlite3* db,const char* sql,Args&&... args,std::index_sequence<Is...>)
{
    sqlite3_stmt* statement{};
    (sqlite3_blob(statement,std::forward<Args>(args),Is + 1),...);

    if constexpr (sizeof...(Args) == 0) sqlite3_step(statement);//Horrible conditional statement. Is there any way of getting rid of it???

    return true;
}

template<typename... Args>
constexpr bool sqlite3_request(sqlite3* db,Args&&... args)
{
    return sqlite3_request_<Args...>(db,sql,std::forward<Args>(args)...,std::make_index_sequence<sizeof...(Args)>{});//Need to change the name because calling function is not able to unambiguosly called the right on
}

//For std::string arguments:
 template<typename... Args>
constexpr bool sqlite3_request(sqlite3* db,const std::string& sql,Args&&... args)//args contain loading data for blobs,if any
{
    return sqlite3_request_<Args...>(db,sql.c_str(),std::make_index_sequence<sizeof...(Args)>{});// Possible to improve? Unambiguos calling to function if '_' eliminated in function calling and declaration
}

int main()
{
    const std::ostringstream data;
    std::string sql = "INSERT INTO scenarios(file) VALUES(?);";//file is a BLOB field
    sqlite3_request(db,data);
}

请注意我已经清理并模拟了所有 sqlLite 函数。这不是关于 sqlLite 的问题,而是关于改进模板样式的问题。

此外,这里是指向所述源代码的coliru链接http://coliru.stacked-crooked.com/a/ec8e8bf65f451b20

解决方法

有一些方法可以提供帮助。对于第一个问题,您可以使用命名空间来修复不明确的调用。关于第二个问题,如果不想使用if constexpr,也可以将nullptr_t定义为参数类型,然后用nullptr调用。这可能不符合您的大部分期望,但希望您对此感到满意

#include <string>
#include <sstream>
#include <utility>

class sqlite3 {};
class sqlite3_stmt {};
sqlite3* db;

void sqlite3_blob(sqlite3_stmt*,std::nullptr_t,int) {}

//Auxiliary BLOB functions
template<typename T>
bool sqlite3_blob(sqlite3_stmt*,const T& data,int col);

template<>
bool sqlite3_blob<std::ostringstream>(sqlite3_stmt* statement,const std::ostringstream& data,int col)
{
    //std::string buffer{ data.str() };
    return true;
}
namespace details {
//sqlite3 automatization request
template<typename... Args,std::size_t... Is>
constexpr bool sqlite3_request(sqlite3* db,const char* sql,Args&&... args,std::index_sequence<Is...>)
{
    sqlite3_stmt* statement{};
    (sqlite3_blob(statement,std::forward<Args>(args),Is + 1),...);

    return true;
}
}

template<typename... Args>
constexpr bool sqlite3_request(sqlite3* db,Args&&... args)
{
    return details::sqlite3_request<Args...>(db,sql,std::forward<Args>(args)...,std::make_index_sequence<sizeof...(Args)>{});//Need to change the name because calling function is not able to unambiguosly called the right on
}

//For std::string arguments:
 template<typename... Args>
constexpr bool sqlite3_request(sqlite3* db,const std::string& sql,Args&&... args)//args contain loading data for blobs,if any
{
    return details::sqlite3_request<Args...>(db,sql.c_str(),std::make_index_sequence<sizeof...(Args)>{});// Possible to improve? Unambiguos calling to function if '_' eliminated in function calling and declaration
}

int main()
{
    const std::ostringstream data;
    std::string sql = "INSERT INTO scenarios(file) VALUES(?);";//file is a BLOB field
    sqlite3_request(db,data);
    sqlite3_request(db,nullptr);
}