如何在运行时在 C++ 中创建参数列表以将其传递给模板函数(...,Ts &&... 值),如 InsertOrUpdateMutationBuilder

How create argument list in C++ during runtime to pass this to a template function(..., Ts &&... values) like in InsertOrUpdateMutationBuilder

我想用 C++ 编写 google-cloud-spanner。

我使用的 api-package 来自 https://github.com/googleapis/google-cloud-cpp.
在第 1677ff 行的代码 https://github.com/googleapis/google-cloud-cpp/blob/main/google/cloud/spanner/samples/samples.cc 中,可以看到“InsertOrUpdateMutationBuilder”中的方法“EmplaceRow”,或者从第 1739 行到 1743 行中不是很简单的“MakeInsertOrUpdateMutation”。
正在查看
https://googleapis.dev/cpp/google-cloud-spanner/latest/namespacegoogle_1_1cloud_1_1spanner.html
可以看到“EmplaceRow”和“MakeInsertOrUpdateMutation”的示例代码。 更准确地说,您可以在
上查看“EmplaceRow”示例代码 https://googleapis.dev/cpp/google-cloud-spanner/latest/namespacegoogle_1_1cloud_1_1spanner.html#a3451b640c4ee19df694fa0539047fcdc

上的“MakeInsertOrUpdateMutation”示例代码 https://googleapis.dev/cpp/google-cloud-spanner/latest/namespacegoogle_1_1cloud_1_1spanner.html#aced68ba9bc789f44693ad29962fc6ed6

我的问题是:
我如何创建一个变量(!)参数列表以将它们传递到“EmplaceRow”或“MakeInsertOrUpdateMutation”中作为“Ts &&... values”。
而“可变参数列表”意味着这个“列表”(不是std::list)可以以上述方式用作“Ts &&... values”-list.

直到现在我已经搜索了很多解决方案,但没有找到合适的解决方案:

  1. 两个模板函数,使用 std::tuple 将其元组元素扩展到“Ts &&... 值”列表。
  2. 两个模板函数,使用 std::array 将其数组元素扩展到“Ts &&... values”列表。

两种解决方案都“不错”但没有用!
我想在运行时处理具有不同列数的不同 table,但是 std::tuple 和 std::array 的大小必须在编译时固定(!)。
因此,无法通过 std::tuple 和 std::array.

解决在运行时创建“Ts &&... values”列表

所以...我如何从 std::vector、std::list 或其他容器类型创建,这些容器类型可以创建、调整大小并填充“spanner::Value”值,“Ts &&... values”-list 将其传递给“EmplaceRow”或“MakeInsertOrUpdateMutation”。

这是我将 std::tuple 扩展为“Ts &&... values”列表的代码:

template <typename Tuple, std::size_t... I>
int myInsrtOrUpdMutBldEmplaceRowBuild_Tup(confDataProc::processConfigData testA,
                                          Tuple const& tuple,
                                          std::index_sequence<I...>)
{
  namespace spanner = ::google::cloud::spanner;

  //std::cout << "the second 'myInsrtOrUpdMutBldEmplaceRowBuild_Tup'" << std::endl;
  auto client = GoClSp::MakeSampleClient(testA.getProjectID(), 
                                         testA.getInstanceID(),
                                         testA.getDatabaseID());
  auto commit = client.Commit(spanner::Mutations{
                              spanner::InsertOrUpdateMutationBuilder(
                                        testA.getTableName(),
                                        testA.getColumnNamesOfTable())
                                        .EmplaceRow(std::get<I>(tuple)...)
                                            .Build()});
  if (!commit)
  {
    throw std::runtime_error(commit.status().message());
  }

  return 0;
}
template <typename Tuple>
int myInsrtOrUpdMutBldEmplaceRowBuild_Tup(confDataProc::processConfigData testA,
                                          Tuple const& tuple)
{
  //std::cout << "the first 'myInsrtOrUpdMutBldEmplaceRowBuild_Tup'" << std::endl;

  int iRetVal = myInsrtOrUpdMutBldEmplaceRowBuild_Tup(testA, 
                        tuple,
                        std::make_index_sequence<std::tuple_size<Tuple>::value>());

  return iRetVal;
}

此代码有效,但最大的问题是 std::tuple 的大小必须在编译时已知,并且不能在运行时使用变量 size/length 创建。 size/length 在此上下文中是已处理的 table.

的列数

也许解决方案对于其他(更好的)程序员比我更明显,或者可能很难。但是无论如何,我们总是欢迎截取有用的代码或有用的 link。

顺便说一句:
根据我的经验,这与 'classic' 可变参数非常不同。
我无法更改方法“EmplaceRow”或“MakeInsertOrUpdateMutation”的行为 - 如果我想将“Ts &&... 值”列表更改为更简单的“std::vectorspanner::值值".

另一方面:
如果有其他 C++ 函数可以在 cloud-spanner table 中插入或更新 table 行,我不知道,请告诉我。
我“只”需要一个在 C++ 中插入或更新一行 table 的解决方案,我不坚持上述方式。

EmplaceRow 替换为 AddRow 就可以了。

您无法在此处以实用的方式将运行时参数转换为模板参数。 (我无法向您展示如何做,但请相信我,这里的计划很糟糕;我只是不说“不可能”,因为我不喜欢说谎。)

我发现 google 的 C++ 文档需要愿意并且能够阅读原始 headers 和源代码。在这里,我找到了定义了 EmplaceRow 的 class 并查找了它的作用或替代方法。

Emplace 在 C++ 术语中的意思是“完美转发到存储”;通常附近有一个不完善的转发方法(例如,push_back vs emplace_back),当模板妨碍时。