#c #c 17 #variadic-templates #parameter-pack
Вопрос:
Мне удалось создать библиотеку, которая поможет мне делать запросы в библиотеку SQLite, особенно в тех, которые связаны с файлами больших двоичных объектов.
Проблема возникла из-за того, что я чувствую, что реализацию можно улучшить, но у меня недостаточно знаний для ее достижения. Любая помощь в решении этой пары вопросов:
- Некоторые функции могут быть вызваны с помощью оператора SQL в виде строки c-pure или строки std::. Оба они, наконец, вызывают окончательную реализацию одной и той же функции. Проблема возникает при однозначном вызове функции шаблона, если я попытаюсь удалить » _ » для объявления и вызова функции (см. Исходный код). Я понимаю, что это незначительная проблема, но мне интересно, есть ли какой-нибудь способ ее достичь.
- Я попытался использовать один и тот же код для запросов, использующих файлы для загрузки больших двоичных объектов в БД, и для запросов, не использующих большие двоичные объекты. Разница заключается в том, что первые используют потоки файлов в качестве параметров, а вторые не имеют никаких параметров потока. 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 Tamp; data, int col);
template<>
bool sqlite3_blob<std::ostringstream>(sqlite3_stmt* statement, const std::ostringstreamamp; 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, Argsamp;amp;... 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, const char* sql, Argsamp;amp;... 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::stringamp; sql, Argsamp;amp;... args)//args contain loading data for blobs, if any
{
return sqlite3_request_<Args...>(db, sql.c_str(), std::forward<Args>(args)..., 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, sql, data);
}
Пожалуйста, обратите внимание, что у меня есть чистые и имитирующие все функции SQLLite. Это вопрос не о SQLLite, а об улучшении стиля шаблонов.
Кроме того, здесь приведена ссылка http://coliru.stacked-crooked.com/a/ec8e8bf65f451b20
coliru на указанный исходный код.
Комментарии:
1. Некоторые функции могут быть вызваны с помощью оператора SQL в виде строки c-pure или строки std:: Для них не нужно предоставлять отдельные перегрузки.
const std::string amp;
будет привязываться к обоим.2. @Пол Сандерс: Да, вы правы, но я поступил так из соображений эффективности. Некоторые запросы фиксированы и определены во время компиляции, поэтому использование строки std::всегда заставляет их использовать динамическую память и кучу. Это мое предположение, возможно, я могу ошибаться, и современные компиляторы достаточно умны, чтобы оптимизировать эти строки самостоятельно, используя std::string.
Ответ №1:
Есть несколько способов помочь. Для первого вопроса вы можете использовать пространства имен, чтобы исправить неоднозначные вызовы. Что касается второго вопроса , в случае , если вы не хотите его использовать 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 Tamp; data, int col);
template<>
bool sqlite3_blob<std::ostringstream>(sqlite3_stmt* statement, const std::ostringstreamamp; 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, Argsamp;amp;... 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, const char* sql, Argsamp;amp;... 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::stringamp; sql, Argsamp;amp;... args)//args contain loading data for blobs, if any
{
return details::sqlite3_request<Args...>(db, sql.c_str(), std::forward<Args>(args)..., 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, sql, data);
sqlite3_request(db, sql, nullptr);
}