【问题标题】:Template parameter pack peel args in pairs模板参数包成对剥离args
【发布时间】:2021-08-27 20:39:39
【问题描述】:

我想为 ESP2866 微控制器创建一个函数,将任意数量的配置保存到文件系统上的配置文件中。我找到了一种方法,我想知道它是否会更好。

// Saves the configuration values to the file system
template <typename... Args>
void SaveConfig(const char *name, String &value, Args &...args)
{
    Serial.println("Saving config...");
    StaticJsonDocument<JSON_OBJECT_SIZE(2) + 200> doc;
    SetData(doc, name, value, args...);

    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile)
        Serial.println("Failed to open config file for writing!");

    serializeJson(doc, configFile);
    serializeJson(doc, Serial);
    configFile.close();
}

我需要做的就是:

doc[name] = value;

对于参数包中的每对参数。我的解决方案是我创建了一个新函数 SetData(),它使用参数包参数调用自身,每次迭代都剥离两个参数:

template <typename... Args>
static void SetData(JsonDocument &doc, const char *name, String &value, Args &...args)
{
    doc[name] = value;
    SetData(doc, args...);
}

但这会产生另一个问题。当参数包“用完”时,它想在没有参数的情况下调用 SetData()。所以现在我必须创建一个不带参数的函数的重载(除了 doc)。

那么有没有更好的方法呢?

【问题讨论】:

  • 你坚持模板吗?我会使用结构体(或std::pairs)的std::vector(或可能std::initializer_list),
  • std 在微控制器上并不真正可用。我的意思是它有点工作,但 std::vector 在堆上分配内存。
  • std::initializer_list 没有。我也会担心模板(尤其是像你这样的递归模板)会使二进制文件膨胀。
  • @FlucTuAte。 STL 在 MCU 上不可用也不正确。它可用,可以使用,为堆保留部分内存是没有问题的。但是,确实必须非常小心地使用它。较小的堆大小和频繁的分配很容易导致内存碎片化到无法进行进一步分配的程度。
  • 如果你受限于 C++11,我很确定你所拥有的解决方案是尽可能干净的。使用 C++17,您也许可以使用折叠表达式对其进行改进。

标签: c++ c++11 arduino variadic-templates microcontroller


【解决方案1】:

如果你真的想使用模板而不是容器,你可以尝试以下方法:

template<typename ...Args, std::size_t ...I>
void SetDataImpl(JsonDocument& doc, std::tuple<Args...> tup, std::index_sequence<I...>) {
  int dummy[] = {
    (doc[std::get<2*I>(tup)] = std::get<2*I+1>(tup), 0)...
  };
}

template<typename ...Args>
void SetData(JsonDocument& doc, Args &...args) {
  static_assert(sizeof...(args) % 2 == 0, "");
  SetDataImpl(doc, std::forward_as_tuple(args...), std::make_index_sequence<sizeof...(args) / 2>{});
}

但正如@HolyBlackCat 所说,这种方式会更好。

void SetData(JsonDocument& doc, std::initializer_list<std::pair<const char*, String>> il = {}) {
  for(const auto& elem : il) { // Just auto& maybe. Depends on json library implementation
    doc[elem.first] = elem.second;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-17
    • 1970-01-01
    • 2021-12-22
    • 2014-07-12
    • 1970-01-01
    • 2020-10-16
    • 2017-03-03
    • 2015-07-12
    相关资源
    最近更新 更多