在编译时获取可变参数模板的索引和值

Get index and value of variadic template at compile time

提问人:Daniil Rozanov 提问时间:11/10/2023 最后编辑:Daniil Rozanov 更新时间:11/11/2023 访问量:55

问:

我有一个看起来像这样的函数

template <typename... Rets, typename... Args>
std::tuple<Rets...> call_nn(std::string_view query, Args... args)
{
  pqxx::work w(con_);
  pqxx::row res = w.exec_params1(pqxx::zview(query), args...);
  w.commit();
  return // std::tuple<Rets...>((res[std::index_sequence_for<Rets>{}].as<Rets>())...); doesn't work
}

pqxx::row表示来自 Postgres 的结果表的一行。它支持将列值获取为 。res[0].as<int>()

问题是我不知道如何扩展可变参数模板参数以访问类型索引和类型本身。我应该放什么来代替????

return std::tuple(ret[/*???*/].as<Rets>()...);

我试图定义和扩展,但随后编译器发出警告int i = 0res[i++].as<Rets>()...

Multiple unsequenced modifications to 'i'

因此,也许有一些更好的方法可以在没有运行时变量的情况下将 return 语句扩展为以下示例

return std::tuple(ret[0].as<X>(), ret[1].as<Y>(), /*...*/ ret[n].as<Z>() );
C++ 模板 C++17 variadic-templates libpqxx

评论


答:

3赞 Artyer 11/10/2023 #1

您希望为 : 中的值创建第二个参数包:index_sequence

template <typename... Rets, std::size_t... Idxs, typename... Args>
std::tuple<Rets...> call_nn(std::index_sequence<Idxs...>, std::string_view query, Args&... args)
{
  pqxx::work w(con_);
  pqxx::row res = w.exec_params1(pqxx::zview(query), args...);
  w.commit();
  return std::tuple<Rets...>((res[Idxs].as<Rets>())...);
}

template <typename... Rets, typename... Args>
std::tuple<Rets...> call_nn(std::string_view query, Args... args)
{
    return call_nn<Rets...>(std::index_sequence_for<Rets...>{}, query, args...);
}
2赞 Red.Wave 11/10/2023 #2

从 C++20 开始,lambda 表达式可以具有显式模板参数列表。在定义后立即调用 lambda 已成为一种普遍的现代习语。这两种思想的结合在可变模板编程中非常常见。但与以往一样,主要规则是包扩展表达式中的所有参数包一起展开,并且需要具有相同的大小:

return [&res] <std::size_t ... i>
       (std::index_sequence<i...>) {
       return std::tuple{ res[i].as<Rets>()... };
} (std::index_sequence_for<Rets...>{});

请注意,在内部 return 语句中,并同时展开。iRets

在上面的代码中,我使用了 C++20 CTAD 语法来缩短代码序列;这就是为什么后面没有 .在这种情况下,显式参数列表通常用于转换,或者当类参数无法从构造函数参数中完全推导出时。tuple<Rets...>