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

折叠可变参数模板函数以在每个模板类型上调用函数,同时提供顺序

如何解决折叠可变参数模板函数以在每个模板类型上调用函数,同时提供顺序

我最近发现了 sqlite,它对我来说似乎是一个很棒的嵌入式数据库。我能找到的唯一(而且非常小的)问题是关于它的 C 接口以及它如何迫使您键入大量样板代码,所以我想知道我们是否可以改进使用可变参数模板和 C++17 折叠功能那一点。

不幸的是,我知道我想要什么,但我无法自己开发。

解决方案的理想先决条件:

  1. 基于 C++17 或更低版本的解决方案(但遗憾的是不是 C++20)
  2. 摆脱辅助模板专用函数应该是一个很大的优势(也许是对 if constexpr(type_trait) 的巧妙使用?)

这是我当前的代码,以及一个关于可变参数模板函数应该如何表现的注释示例:

#include <iostream>
#include <tuple>

// Fake mock pretending the interface for sqlite3 (just to avoid have to install,link and include the real project).
// Please,do NOT change anything here.
unsigned char buffer[] = { 't','e','s','t' };
const int sqlite3_column_int(int iCol) { return 5; }
const unsigned char* sqlite3_column_text(int iCol) { return buffer; }
// End of unmodificable mock.

// Auxiliary functions:
template<typename T>
T sqlite3_column(int col);

template<>
int sqlite3_column<int>(int col) { return sqlite3_column_int(col); }

template<>
std::string sqlite3_column<std::string>(int col) { return reinterpret_cast<const char*>(sqlite3_column_text(col)); }

// What I would like to have available:
template<typename... Args>
auto sqlite3_record() -> std::tuple<Args...>
{
    return std::make_tuple((sqlite3_column<Args>(N?),...));
}

//It should behabe as this example:
//std::tuple<int,int,std::string,std::string> sqlite3_record_example()
//{
//    return std::make_tuple( sqlite3_column<int>(0),sqlite3_column<int>(1),sqlite3_column<std::string>(2),sqlite3_column<std::string>(3) );
//}


int main()
{
    auto [i1,i2,s1,s2] = sqlite3_record<int,std::string>();
    std::cout << i1 << " / " << i2 << " / " << s1 << " / " << s2;
    //It should return 5 / 5 / test / test
}

这是一个 Coliru 链接http://coliru.stacked-crooked.com/a/52e5acd9d92a39e8

请原谅模板参数位置的可怕 N?

解决方法

template<typename... Args,std::size_t...Is>
auto sqlite3_record(sqlite3_stmt* statement,std::index_sequence<Is...>)
{
  return std::make_tuple(sqlite3_column<Args>(statement,Is)...);
}
template<typename... Args>
auto sqlite3_record(sqlite3_stmt* statement){
  return sqlite3_record<Args...>(statement,std::make_index_sequence<sizeof...(Args)>{});
}

你只需要数数,对吗?

为了计算包装数量,我们制作了第二个包装,其中包含数量。

然后我们可以一次展开两个包,只要它们的大小相同。

std::make_index_sequence<N>{} 返回类型为 index_sequence<0,1, ... ,n-2,n-1> 的对象,因此通过匹配函数签名,我们可以获得包含我们想要的索引的包。

最简单的方法是创建一个辅助函数来获取该包,并在那里进行双参数包扩展,但还有其他方法可以获取整数包。

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

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?