获取 C++ 可变模板参数的序号
Get ordinal number of C++ variadic template parameter
我想从variadic template
个参数中检索每个参数的索引,目前我正在使用这种方法:
来自第三方库:
struct statement {
template <typename T>
void bind(int, T t) { // ....
}
};
我的代码:
template <unsigned Index, typename T>
void bind(statement& stmt, T t) {
stmt.bind(Index, t);
}
template <unsigned Index, typename T, typename... Args>
void bind(statement& stmt, T t, Args... args) {
bind<Index>(stmt, t);
bind<Index + 1>(stmt,args...);
}
template <typename... Args>
void bind_all(statement& stmt, Args... args) {
constexpr int Index = 0;
bind<Index>(stmt, args...);
}
用法:
statement stmt;
prepare(stmt, "insert into tab (a,b,c,d,e,f) values(?,?,?,?,?,?)");
bind_all(stmt, 1,1.24f, 3.14, "Hello", std::string{"World"}, true);
我的问题:是否有更好的方法来实现此目的,以获得 variadic template
参数的序号?
编辑:
我想使用此实现来包装 sql prepared statement
并将特定参数绑定到特定索引。
这是我想要包装的代码示例,而不是单独列出每个绑定,我想调用 bind_all
prepare(stmt, "insert into tab (a, b) values (?, ?);");
const int eight_int = 8;
stmt.bind(0, &eight_int);
const string eight_str = "eight";
stmt.bind(1, eight_str.c_str());
execute(stmt);
通过简单扩展(可以在 C++17 中使用 fold expression)
struct statement
{
template<class T>
void bind(int index, T&& arg)
{
// magic
}
};
template<class... Args>
void BindAll(statement& stmt, Args&&... args)
{
using swallow = int[];
int idx = 0;
(void)swallow{0, (void (stmt.bind(idx++, std::forward<Args>(args))), 0)...};
}
我对 API 进行了一些改动,但我认为它与您的代码非常接近。
用法:
statement stmt;
BindAll(stmt, 1, 1.2, 1.3f, true, "abc");
Demo
您可以使用 std::index_sequence
创建包含匹配索引的第二个模板参数包:
template <typename... Args, size_t... Is>
void bind_all_helper(std::index_sequence<Is...>, Args... args) {
int dummy[]{(bind<Is>(args), 0)...};
(void)dummy; // just to avoid unused variable warnings
}
template <typename... Args>
void bind_all(Args... args) {
bind_all_helper(std::make_index_sequence<sizeof...(args)>{}, args...);
}
这使用虚拟数组定义和逗号运算符来创建对 bind
的调用序列。例如,给定 bind_all(1, 3.14)
,数组定义将扩展为如下所示:
int dummy[] {
(bind<0>(1), 0),
(bind<1>(3.14), 0)
};
数组的每个元素最终都是 0
,但其计算具有调用 bind<N>(arg)
的副作用。
使用 C++17,dummy
数组定义可以替换为折叠表达式,但如果您仅限于 C++14,那显然不是一个选项。
为什么不为此使用 std::tuple
。
#include <utility>
#include <tuple>
template<typename T, std::size_t... Index>
void doBind(Statement& st, T const& tuple, std::index_sequence<Index...> const&)
{
// Using C++17 fold expression
((st.bind(Index, std::get<Index>(tuple))),...);
// Using C++11 dummy variable
int dummy[] = {0, (st.bind(Index, std::get<Index>(tuple)),0)...};
(void)dummy; // to prevent unused variable warning.
}
template<typename... Args>
void prepare(std::string const& sql, Args&&... args)
{
Statement statement;
prepare(statement, sql);
doBind(statement, std::make_tuple(args...), std::make_index_sequence<sizeof...(args)>());
execute(statement);
}
我想从variadic template
个参数中检索每个参数的索引,目前我正在使用这种方法:
来自第三方库:
struct statement {
template <typename T>
void bind(int, T t) { // ....
}
};
我的代码:
template <unsigned Index, typename T>
void bind(statement& stmt, T t) {
stmt.bind(Index, t);
}
template <unsigned Index, typename T, typename... Args>
void bind(statement& stmt, T t, Args... args) {
bind<Index>(stmt, t);
bind<Index + 1>(stmt,args...);
}
template <typename... Args>
void bind_all(statement& stmt, Args... args) {
constexpr int Index = 0;
bind<Index>(stmt, args...);
}
用法:
statement stmt;
prepare(stmt, "insert into tab (a,b,c,d,e,f) values(?,?,?,?,?,?)");
bind_all(stmt, 1,1.24f, 3.14, "Hello", std::string{"World"}, true);
我的问题:是否有更好的方法来实现此目的,以获得 variadic template
参数的序号?
编辑:
我想使用此实现来包装 sql prepared statement
并将特定参数绑定到特定索引。
这是我想要包装的代码示例,而不是单独列出每个绑定,我想调用 bind_all
prepare(stmt, "insert into tab (a, b) values (?, ?);");
const int eight_int = 8;
stmt.bind(0, &eight_int);
const string eight_str = "eight";
stmt.bind(1, eight_str.c_str());
execute(stmt);
通过简单扩展(可以在 C++17 中使用 fold expression)
struct statement
{
template<class T>
void bind(int index, T&& arg)
{
// magic
}
};
template<class... Args>
void BindAll(statement& stmt, Args&&... args)
{
using swallow = int[];
int idx = 0;
(void)swallow{0, (void (stmt.bind(idx++, std::forward<Args>(args))), 0)...};
}
我对 API 进行了一些改动,但我认为它与您的代码非常接近。
用法:
statement stmt;
BindAll(stmt, 1, 1.2, 1.3f, true, "abc");
Demo
您可以使用 std::index_sequence
创建包含匹配索引的第二个模板参数包:
template <typename... Args, size_t... Is>
void bind_all_helper(std::index_sequence<Is...>, Args... args) {
int dummy[]{(bind<Is>(args), 0)...};
(void)dummy; // just to avoid unused variable warnings
}
template <typename... Args>
void bind_all(Args... args) {
bind_all_helper(std::make_index_sequence<sizeof...(args)>{}, args...);
}
这使用虚拟数组定义和逗号运算符来创建对 bind
的调用序列。例如,给定 bind_all(1, 3.14)
,数组定义将扩展为如下所示:
int dummy[] {
(bind<0>(1), 0),
(bind<1>(3.14), 0)
};
数组的每个元素最终都是 0
,但其计算具有调用 bind<N>(arg)
的副作用。
使用 C++17,dummy
数组定义可以替换为折叠表达式,但如果您仅限于 C++14,那显然不是一个选项。
为什么不为此使用 std::tuple
。
#include <utility>
#include <tuple>
template<typename T, std::size_t... Index>
void doBind(Statement& st, T const& tuple, std::index_sequence<Index...> const&)
{
// Using C++17 fold expression
((st.bind(Index, std::get<Index>(tuple))),...);
// Using C++11 dummy variable
int dummy[] = {0, (st.bind(Index, std::get<Index>(tuple)),0)...};
(void)dummy; // to prevent unused variable warning.
}
template<typename... Args>
void prepare(std::string const& sql, Args&&... args)
{
Statement statement;
prepare(statement, sql);
doBind(statement, std::make_tuple(args...), std::make_index_sequence<sizeof...(args)>());
execute(statement);
}