微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

获取 C++ 可变参数模板参数的序号 Demo

如何解决获取 C++ 可变参数模板参数的序号 Demo

我想从 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,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::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);
}
,

您可以使用 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...);
}

Live Demo

这使用虚拟数组定义和逗号运算符来创建对 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,这显然不是一个选项。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。